hdjs
Version:
hdjs framework
309 lines (255 loc) • 9.27 kB
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();
}
});
});