309 lines
9.0 KiB
JavaScript
309 lines
9.0 KiB
JavaScript
/**
|
||
* @fileOverview 队列
|
||
*/
|
||
define([
|
||
'../base',
|
||
'../uploader',
|
||
'../queue',
|
||
'../file',
|
||
'../lib/file',
|
||
'../runtime/client',
|
||
'./widget'
|
||
], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {
|
||
|
||
var $ = Base.$,
|
||
rExt = /\.\w+$/,
|
||
Status = WUFile.Status;
|
||
|
||
return Uploader.register({
|
||
name: 'queue',
|
||
|
||
init: function( opts ) {
|
||
var me = this,
|
||
deferred, len, i, item, arr, accept, runtime;
|
||
|
||
if ( $.isPlainObject( opts.accept ) ) {
|
||
opts.accept = [ opts.accept ];
|
||
}
|
||
|
||
// accept中的中生成匹配正则。
|
||
if ( opts.accept ) {
|
||
arr = [];
|
||
|
||
for ( i = 0, len = opts.accept.length; i < len; i++ ) {
|
||
item = opts.accept[ i ].extensions;
|
||
item && arr.push( item );
|
||
}
|
||
|
||
if ( arr.length ) {
|
||
accept = '\\.' + arr.join(',')
|
||
.replace( /,/g, '$|\\.' )
|
||
.replace( /\*/g, '.*' ) + '$';
|
||
}
|
||
|
||
me.accept = new RegExp( accept, 'i' );
|
||
}
|
||
|
||
me.queue = new Queue();
|
||
me.stats = me.queue.stats;
|
||
|
||
// 如果当前不是html5运行时,那就算了。
|
||
// 不执行后续操作
|
||
if ( this.request('predict-runtime-type') !== 'html5' ) {
|
||
return;
|
||
}
|
||
|
||
// 创建一个 html5 运行时的 placeholder
|
||
// 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。
|
||
deferred = Base.Deferred();
|
||
this.placeholder = runtime = new RuntimeClient('Placeholder');
|
||
runtime.connectRuntime({
|
||
runtimeOrder: 'html5'
|
||
}, function() {
|
||
me._ruid = runtime.getRuid();
|
||
deferred.resolve();
|
||
});
|
||
return deferred.promise();
|
||
},
|
||
|
||
|
||
// 为了支持外部直接添加一个原生File对象。
|
||
_wrapFile: function( file ) {
|
||
if ( !(file instanceof WUFile) ) {
|
||
|
||
if ( !(file instanceof File) ) {
|
||
if ( !this._ruid ) {
|
||
throw new Error('Can\'t add external files.');
|
||
}
|
||
file = new File( this._ruid, file );
|
||
}
|
||
|
||
file = new WUFile( file );
|
||
}
|
||
|
||
return file;
|
||
},
|
||
|
||
// 判断文件是否可以被加入队列
|
||
acceptFile: function( file ) {
|
||
var invalid = !file || !file.size || this.accept &&
|
||
|
||
// 如果名字中有后缀,才做后缀白名单处理。
|
||
rExt.exec( file.name ) && !this.accept.test( file.name );
|
||
|
||
return !invalid;
|
||
},
|
||
|
||
|
||
/**
|
||
* @event beforeFileQueued
|
||
* @param {File} file File对象
|
||
* @description 当文件被加入队列之前触发,此事件的handler返回值为`false`,则此文件不会被添加进入队列。
|
||
* @for Uploader
|
||
*/
|
||
|
||
/**
|
||
* @event fileQueued
|
||
* @param {File} file File对象
|
||
* @description 当文件被加入队列以后触发。
|
||
* @for Uploader
|
||
*/
|
||
|
||
_addFile: function( file ) {
|
||
var me = this;
|
||
|
||
file = me._wrapFile( file );
|
||
|
||
// 不过类型判断允许不允许,先派送 `beforeFileQueued`
|
||
if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {
|
||
return;
|
||
}
|
||
|
||
// 类型不匹配,则派送错误事件,并返回。
|
||
if ( !me.acceptFile( file ) ) {
|
||
me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );
|
||
return;
|
||
}
|
||
|
||
me.queue.append( file );
|
||
me.owner.trigger( 'fileQueued', file );
|
||
return file;
|
||
},
|
||
|
||
getFile: function( fileId ) {
|
||
return this.queue.getFile( fileId );
|
||
},
|
||
|
||
/**
|
||
* @event filesQueued
|
||
* @param {File} files 数组,内容为原始File(lib/File)对象。
|
||
* @description 当一批文件添加进队列以后触发。
|
||
* @for Uploader
|
||
*/
|
||
|
||
/**
|
||
* @property {Boolean} [auto=false]
|
||
* @namespace options
|
||
* @for Uploader
|
||
* @description 设置为 true 后,不需要手动调用上传,有文件选择即开始上传。
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* @method addFiles
|
||
* @grammar addFiles( file ) => undefined
|
||
* @grammar addFiles( [file1, file2 ...] ) => undefined
|
||
* @param {Array of File or File} [files] Files 对象 数组
|
||
* @description 添加文件到队列
|
||
* @for Uploader
|
||
*/
|
||
addFile: function( files ) {
|
||
var me = this;
|
||
|
||
if ( !files.length ) {
|
||
files = [ files ];
|
||
}
|
||
|
||
files = $.map( files, function( file ) {
|
||
return me._addFile( file );
|
||
});
|
||
|
||
if ( files.length ) {
|
||
|
||
me.owner.trigger( 'filesQueued', files );
|
||
|
||
if ( me.options.auto ) {
|
||
setTimeout(function() {
|
||
me.request('start-upload');
|
||
}, 20 );
|
||
}
|
||
}
|
||
},
|
||
|
||
getStats: function() {
|
||
return this.stats;
|
||
},
|
||
|
||
/**
|
||
* @event fileDequeued
|
||
* @param {File} file File对象
|
||
* @description 当文件被移除队列后触发。
|
||
* @for Uploader
|
||
*/
|
||
|
||
/**
|
||
* @method removeFile
|
||
* @grammar removeFile( file ) => undefined
|
||
* @grammar removeFile( id ) => undefined
|
||
* @grammar removeFile( file, true ) => undefined
|
||
* @grammar removeFile( id, true ) => undefined
|
||
* @param {File|id} file File对象或这File对象的id
|
||
* @description 移除某一文件, 默认只会标记文件状态为已取消,如果第二个参数为 `true` 则会从 queue 中移除。
|
||
* @for Uploader
|
||
* @example
|
||
*
|
||
* $li.on('click', '.remove-this', function() {
|
||
* uploader.removeFile( file );
|
||
* })
|
||
*/
|
||
removeFile: function( file, remove ) {
|
||
var me = this;
|
||
|
||
file = file.id ? file : me.queue.getFile( file );
|
||
|
||
this.request( 'cancel-file', file );
|
||
|
||
if ( remove ) {
|
||
this.queue.removeFile( file );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* @method getFiles
|
||
* @grammar getFiles() => Array
|
||
* @grammar getFiles( status1, status2, status... ) => Array
|
||
* @description 返回指定状态的文件集合,不传参数将返回所有状态的文件。
|
||
* @for Uploader
|
||
* @example
|
||
* console.log( uploader.getFiles() ); // => all files
|
||
* console.log( uploader.getFiles('error') ) // => all error files.
|
||
*/
|
||
getFiles: function() {
|
||
return this.queue.getFiles.apply( this.queue, arguments );
|
||
},
|
||
|
||
fetchFile: function() {
|
||
return this.queue.fetch.apply( this.queue, arguments );
|
||
},
|
||
|
||
/**
|
||
* @method retry
|
||
* @grammar retry() => undefined
|
||
* @grammar retry( file ) => undefined
|
||
* @description 重试上传,重试指定文件,或者从出错的文件开始重新上传。
|
||
* @for Uploader
|
||
* @example
|
||
* function retry() {
|
||
* uploader.retry();
|
||
* }
|
||
*/
|
||
retry: function( file, noForceStart ) {
|
||
var me = this,
|
||
files, i, len;
|
||
|
||
if ( file ) {
|
||
file = file.id ? file : me.queue.getFile( file );
|
||
file.setStatus( Status.QUEUED );
|
||
noForceStart || me.request('start-upload');
|
||
return;
|
||
}
|
||
|
||
files = me.queue.getFiles( Status.ERROR );
|
||
i = 0;
|
||
len = files.length;
|
||
|
||
for ( ; i < len; i++ ) {
|
||
file = files[ i ];
|
||
file.setStatus( Status.QUEUED );
|
||
}
|
||
|
||
me.request('start-upload');
|
||
},
|
||
|
||
/**
|
||
* @method sort
|
||
* @grammar sort( fn ) => undefined
|
||
* @description 排序队列中的文件,在上传之前调整可以控制上传顺序。
|
||
* @for Uploader
|
||
*/
|
||
sortFiles: function() {
|
||
return this.queue.sort.apply( this.queue, arguments );
|
||
},
|
||
|
||
/**
|
||
* @event reset
|
||
* @description 当 uploader 被重置的时候触发。
|
||
* @for Uploader
|
||
*/
|
||
|
||
/**
|
||
* @method reset
|
||
* @grammar reset() => undefined
|
||
* @description 重置uploader。目前只重置了队列。
|
||
* @for Uploader
|
||
* @example
|
||
* uploader.reset();
|
||
*/
|
||
reset: function() {
|
||
this.owner.trigger('reset');
|
||
this.queue = new Queue();
|
||
this.stats = this.queue.stats;
|
||
},
|
||
|
||
destroy: function() {
|
||
this.reset();
|
||
this.placeholder && this.placeholder.destroy();
|
||
}
|
||
});
|
||
|
||
}); |