/**
|
* @fileoverview 异步文件上传组件
|
* @author 剑平(明河)<minghe36@126.com>,紫英<daxingplay@gmail.com>
|
**/
|
KISSY.add('gallery/form/1.3/uploader/base', function (S, Base, Node, UrlsInput, IframeType, AjaxType, FlashType, HtmlButton, SwfButton, Queue) {
|
var EMPTY = '', $ = Node.all, LOG_PREFIX = '[uploader]:';
|
|
/**
|
* @name Uploader
|
* @class 异步文件上传组件,支持ajax、flash、iframe三种方案
|
* @constructor
|
* @extends Base
|
* @requires UrlsInput
|
* @requires IframeType
|
* @requires AjaxType
|
* @param {Object} config 组件配置(下面的参数为配置项,配置会写入属性,详细的配置说明请看属性部分)
|
* @param {Button} config.button *,Button按钮的实例
|
* @param {Queue} config.queue *,Queue队列的实例
|
* @param {String|Array} config.type *,采用的上传方案
|
* @param {Object} config.serverConfig *,服务器端配置
|
* @param {String} config.urlsInputName *,存储文件路径的隐藏域的name名
|
* @param {Boolean} config.isAllowUpload 是否允许上传文件
|
* @param {Boolean} config.autoUpload 是否自动上传
|
* @example
|
* var uploader = new Uploader({button:button,queue:queue,serverConfig:{action:'test.php'}})
|
*/
|
function Uploader(config) {
|
var self = this;
|
//调用父类构造函数
|
Uploader.superclass.constructor.call(self, config);
|
}
|
|
|
S.mix(Uploader, /** @lends Uploader*/{
|
/**
|
* 上传方式,{AUTO:'auto', IFRAME:'iframe', AJAX:'ajax', FLASH:'flash'}
|
*/
|
type:{AUTO:'auto', IFRAME:'iframe', AJAX:'ajax', FLASH:'flash'},
|
/**
|
* 组件支持的事件列表,{ RENDER:'render', SELECT:'select', START:'start', PROGRESS : 'progress', COMPLETE:'complete', SUCCESS:'success', UPLOAD_FILES:'uploadFiles', CANCEL:'cancel', ERROR:'error' }
|
*
|
*/
|
event:{
|
//运行
|
RENDER:'render',
|
//选择完文件后触发
|
SELECT:'select',
|
//开始上传后触发
|
START:'start',
|
//正在上传中时触发
|
PROGRESS:'progress',
|
//上传完成(在上传成功或上传失败后都会触发)
|
COMPLETE:'complete',
|
//上传成功后触发
|
SUCCESS:'success',
|
//批量上传结束后触发
|
UPLOAD_FILES:'uploadFiles',
|
//取消上传后触发
|
CANCEL:'cancel',
|
//上传失败后触发
|
ERROR:'error',
|
//初始化默认文件数据时触发
|
RESTORE:'restore'
|
},
|
/**
|
* 文件上传所有的状态,{ WAITING : 'waiting', START : 'start', PROGRESS : 'progress', SUCCESS : 'success', CANCEL : 'cancel', ERROR : 'error', RESTORE: 'restore' }
|
*/
|
status:{
|
WAITING:'waiting',
|
START:'start',
|
PROGRESS:'progress',
|
SUCCESS:'success',
|
CANCEL:'cancel',
|
ERROR:'error',
|
RESTORE:'restore'
|
}
|
});
|
/**
|
* @name Uploader#select
|
* @desc 选择完文件后触发
|
* @event
|
* @param {Array} ev.files 文件完文件后返回的文件数据
|
*/
|
|
/**
|
* @name Uploader#start
|
* @desc 开始上传后触发
|
* @event
|
* @param {Number} ev.index 要上传的文件在队列中的索引值
|
* @param {Object} ev.file 文件数据
|
*/
|
|
/**
|
* @name Uploader#progress
|
* @desc 正在上传中时触发,这个事件在iframe上传方式中不存在
|
* @event
|
* @param {Object} ev.file 文件数据
|
* @param {Number} ev.loaded 已经加载完成的字节数
|
* @param {Number} ev.total 文件总字节数
|
*/
|
|
/**
|
* @name Uploader#complete
|
* @desc 上传完成(在上传成功或上传失败后都会触发)
|
* @event
|
* @param {Number} ev.index 上传中的文件在队列中的索引值
|
* @param {Object} ev.file 文件数据
|
* @param {Object} ev.result 服务器端返回的数据
|
*/
|
|
/**
|
* @name Uploader#success
|
* @desc 上传成功后触发
|
* @event
|
* @param {Number} ev.index 上传中的文件在队列中的索引值
|
* @param {Object} ev.file 文件数据
|
* @param {Object} ev.result 服务器端返回的数据
|
*/
|
|
/**
|
* @name Uploader#error
|
* @desc 上传失败后触发
|
* @event
|
* @param {Number} ev.index 上传中的文件在队列中的索引值
|
* @param {Object} ev.file 文件数据
|
* @param {Object} ev.result 服务器端返回的数据
|
* @param {Object} ev.status 服务器端返回的状态码,status如果是-1,说明是前端验证返回的失败
|
*/
|
|
/**
|
* @name Uploader#cancel
|
* @desc 取消上传后触发
|
* @event
|
* @param {Number} ev.index 上传中的文件在队列中的索引值
|
*/
|
|
/**
|
* @name Uploader#uploadFiles
|
* @desc 批量上传结束后触发
|
* @event
|
*/
|
|
/**
|
* @name Uploader#restore
|
* @desc 添加默认数据到队列后触发
|
* @event
|
*/
|
|
//继承于Base,属性getter和setter委托于Base处理
|
S.extend(Uploader, Base, /** @lends Uploader.prototype*/{
|
/**
|
* 运行组件,实例化类后必须调用render()才真正运行组件逻辑
|
* @return {Uploader}
|
*/
|
render:function () {
|
var self = this, serverConfig = self.get('serverConfig'),
|
type = self.get('type'),
|
UploadType = self.getUploadType(type), uploadType,
|
uploaderTypeEvent = UploadType.event,
|
button;
|
if (!UploadType) return false;
|
button = self._renderButton();
|
//路径input实例
|
self.set('urlsInput', self._renderUrlsInput());
|
self._renderQueue();
|
//如果是flash异步上传方案,增加swfUploader的实例作为参数
|
if (self.get('type') == Uploader.type.FLASH) {
|
S.mix(serverConfig, {swfUploader:button.get('swfUploader')});
|
}
|
serverConfig.fileDataName = self.get('name');
|
//实例化上传方式类
|
uploadType = new UploadType(serverConfig);
|
//监听上传器上传完成事件
|
uploadType.on(uploaderTypeEvent.SUCCESS, self._uploadCompleteHanlder, self);
|
uploadType.on(uploaderTypeEvent.ERROR, function(ev){
|
self.fire(event.ERROR, {status:ev.status, result:ev.result});
|
}, self);
|
//监听上传器上传进度事件
|
if (uploaderTypeEvent.PROGRESS) uploadType.on(uploaderTypeEvent.PROGRESS, self._uploadProgressHandler, self);
|
//监听上传器上传停止事件
|
uploadType.on(uploaderTypeEvent.STOP, self._uploadStopHanlder, self);
|
self.set('uploadType', uploadType);
|
self.fire(Uploader.event.RENDER);
|
return self;
|
},
|
/**
|
* 上传指定队列索引的文件
|
* @param {Number} index 文件对应的在上传队列数组内的索引值
|
* @example
|
* //上传队列中的第一个文件,uploader为Uploader的实例
|
* uploader.upload(0)
|
*/
|
upload:function (index) {
|
if (!S.isNumber(index)) return false;
|
var self = this, uploadType = self.get('uploadType'),
|
type = self.get('type'),
|
queue = self.get('queue'),
|
file = queue.get('files')[index],
|
uploadParam;
|
if (!S.isPlainObject(file)) {
|
S.log(LOG_PREFIX + '队列中不存在id为' + index + '的文件');
|
return false;
|
}
|
//如果有文件正在上传,予以阻止上传
|
if (self.get('curUploadIndex') != EMPTY) {
|
alert('第' + self.get('curUploadIndex') + '文件正在上传,请上传完后再操作!');
|
return false;
|
}
|
//文件上传域,如果是flash上传,input为文件数据对象
|
uploadParam = file.input.id || file.input;
|
//如果是ajax上传直接传文件数据
|
if (type == 'ajax') uploadParam = file.data;
|
if (file['status'] === 'error') {
|
return false;
|
}
|
//触发文件上传前事件
|
self.fire(Uploader.event.START, {index:index, file:file});
|
//阻止文件上传
|
if (!self.get('isAllowUpload')) return false;
|
//设置当前上传的文件id
|
self.set('curUploadIndex', index);
|
//改变文件上传状态为start
|
queue.fileStatus(index, Uploader.status.START);
|
//开始上传
|
uploadType.upload(uploadParam);
|
},
|
/**
|
* 取消文件上传,当index参数不存在时取消当前正在上传的文件的上传。cancel并不会停止其他文件的上传(对应方法是stop)
|
* @param {Number} index 队列数组索引
|
* @return {Uploader}
|
*/
|
cancel:function (index) {
|
var self = this, uploadType = self.get('uploadType'),
|
queue = self.get('queue'),
|
statuses = Uploader.status,
|
status = queue.fileStatus(index);
|
if (S.isNumber(index) && status != statuses.SUCCESS) {
|
uploadType.stop();
|
queue.fileStatus(index, statuses.CANCEL);
|
} else {
|
//取消上传后刷新状态,更改路径等操作请看_uploadStopHanlder()
|
uploadType.stop();
|
//存在批量上传操作,继续上传其他文件
|
self._continueUpload();
|
}
|
return self;
|
},
|
/**
|
* 停止上传动作
|
* @return {Uploader}
|
*/
|
stop:function () {
|
var self = this;
|
self.set('uploadFilesStatus', EMPTY);
|
self.cancel();
|
return self;
|
},
|
/**
|
* 批量上传队列中的指定状态下的文件
|
* @param {String} status 文件上传状态名
|
* @return {Uploader}
|
* @example
|
* //上传队列中所有等待的文件
|
* uploader.uploadFiles("waiting")
|
*/
|
uploadFiles:function (status) {
|
var self = this;
|
if (!S.isString(status)) status = Uploader.status.WAITING;
|
self.set('uploadFilesStatus', status);
|
self._uploaderStatusFile(status);
|
return self;
|
},
|
/**
|
* 上传队列中的指定状态下的文件
|
* @param {String} status 文件上传状态名
|
* @return {Uploader}
|
*/
|
_uploaderStatusFile:function (status) {
|
var self = this, queue = self.get('queue'),
|
fileIndexs = queue.getIndexs(status);
|
//没有存在需要上传的文件,退出上传
|
if (!fileIndexs.length) {
|
self.set('uploadFilesStatus', EMPTY);
|
self.fire(Uploader.event.UPLOAD_FILES);
|
return false;
|
}
|
//开始上传等待中的文件
|
self.upload(fileIndexs[0]);
|
return self;
|
},
|
/**
|
* 是否支持ajax方案上传
|
* @return {Boolean}
|
*/
|
isSupportAjax:function () {
|
var isSupport = false;
|
try {
|
if (FormData) isSupport = true;
|
} catch (e) {
|
isSupport = false;
|
}
|
return isSupport;
|
},
|
/**
|
* 是否支持flash方案上传
|
* @return {Boolean}
|
*/
|
isSupportFlash:function () {
|
var fpv = S.UA.fpv();
|
return S.isArray(fpv) && fpv.length > 0;
|
},
|
/**
|
* 获取上传方式类(共有iframe、ajax、flash三种方式)
|
* @type {String} type 上传方式
|
* @return {IframeType|AjaxType|FlashType}
|
*/
|
getUploadType:function (type) {
|
var self = this, types = Uploader.type,
|
UploadType;
|
//如果type参数为auto,那么type=['ajax','flash','iframe']
|
if (type == types.AUTO) type = [types.AJAX, types.FLASH, types.IFRAME];
|
//如果是数组,遍历获取浏览器支持的上传方式
|
if (S.isArray(type) && type.length > 0) {
|
S.each(type, function (t) {
|
UploadType = self._getType(t);
|
if (UploadType) return false;
|
});
|
} else {
|
UploadType = self._getType(type);
|
}
|
return UploadType;
|
},
|
/**
|
* 获取上传方式
|
* @param {String} type 上传方式(根据type返回对应的上传类,比如iframe返回IframeType)
|
*/
|
_getType:function (type) {
|
var self = this, types = Uploader.type, UploadType,
|
isSupportAjax = self.isSupportAjax(),
|
isSupportFlash = self.isSupportFlash();
|
switch (type) {
|
case types.IFRAME :
|
UploadType = IframeType;
|
break;
|
case types.AJAX :
|
UploadType = isSupportAjax && AjaxType || false;
|
break;
|
case types.FLASH :
|
UploadType = isSupportFlash && FlashType || false;
|
break;
|
default :
|
S.log(LOG_PREFIX + 'type参数不合法');
|
return false;
|
}
|
if (UploadType) S.log(LOG_PREFIX + '使用' + type + '上传方式');
|
self.set('type', type);
|
return UploadType;
|
},
|
/**
|
* 运行Button上传按钮组件
|
* @return {Button}
|
*/
|
_renderButton:function () {
|
var self = this, button, Button,
|
type = self.get('type'),
|
buttonTarget = self.get('target'),
|
multiple = self.get('multiple'),
|
disabled = self.get('disabled'),
|
name = self.get('name'),
|
config = {name:name, multiple:multiple, disabled:disabled};
|
if (type == Uploader.type.FLASH) {
|
Button = SwfButton;
|
S.mix(config, {size:self.get('swfSize')});
|
} else {
|
Button = HtmlButton;
|
}
|
button = new Button(buttonTarget, config);
|
//监听按钮改变事件
|
button.on('change', self._select, self);
|
//运行按钮实例
|
button.render();
|
self.set('button', button);
|
return button;
|
},
|
/**
|
* 运行Queue队列组件
|
* @return {Queue} 队列实例
|
*/
|
_renderQueue:function () {
|
var self = this, queue = new Queue(),
|
urlsInput = self.get('urlsInput');
|
if (!S.isObject(queue)) {
|
S.log(LOG_PREFIX + 'queue参数不合法');
|
return false;
|
}
|
//将上传组件实例传给队列,方便队列内部执行取消、重新上传的操作
|
queue.set('uploader', self);
|
//监听队列的删除事件
|
queue.on('remove', function (ev) {
|
//删除该文件路径,sUrl为服务器端返回的文件路径,而url是客服端文件路径
|
if (ev.file.sUrl && urlsInput) urlsInput.remove(ev.file.sUrl);
|
});
|
self.set('queue', queue);
|
return queue;
|
},
|
/**
|
* 选择完文件后
|
* @param {Object} ev 事件对象
|
*/
|
_select:function (ev) {
|
var self = this, autoUpload = self.get('autoUpload'),
|
queue = self.get('queue'),
|
curId = self.get('curUploadIndex'),
|
files = ev.files;
|
S.each(files, function (file) {
|
//文件大小,IE浏览器下不存在
|
if (!file.size) file.size = 0;
|
//chrome文件名属性名为fileName,而firefox为name
|
if (!file.name) file.name = file.fileName || EMPTY;
|
//如果是flash上传,并不存在文件上传域input
|
file.input = ev.input || file;
|
});
|
files = self._processExceedMultiple(files);
|
self.fire(Uploader.event.SELECT, {files:files});
|
//阻止文件上传
|
if (!self.get('isAllowUpload')) return false;
|
queue.add(files, function () {
|
//如果不存在正在上传的文件,且允许自动上传,上传该文件
|
if (curId == EMPTY && autoUpload) {
|
self.uploadFiles();
|
}
|
});
|
},
|
/**
|
* 超过最大多选数予以截断
|
*/
|
_processExceedMultiple:function (files) {
|
var self = this, multipleLen = self.get('multipleLen');
|
if (multipleLen < 0 || !S.isArray(files) || !files.length) return files;
|
return S.filter(files, function (file, index) {
|
return index < multipleLen;
|
});
|
},
|
/**
|
* 向上传按钮容器内增加用于存储文件路径的input
|
*/
|
_renderUrlsInput:function () {
|
var self = this, button = self.get('button'), inputWrapper = button.get('target'),
|
name = self.get('urlsInputName'),
|
urlsInput = new UrlsInput(inputWrapper, {name:name});
|
urlsInput.render();
|
return urlsInput;
|
},
|
/**
|
* 当上传完毕后返回结果集的处理
|
*/
|
_uploadCompleteHanlder:function (ev) {
|
var self = this, result = ev.result, status, event = Uploader.event,
|
queue = self.get('queue'), index = self.get('curUploadIndex');
|
if (!S.isObject(result)) return false;
|
//将服务器端的数据保存到队列中的数据集合
|
queue.updateFile(index, {result:result});
|
//文件上传状态
|
status = Number(result.status);
|
// 只有上传状态为1时才是成功的
|
if (status === 1) {
|
//修改队列中文件的状态为success(上传完成)
|
queue.fileStatus(index, Uploader.status.SUCCESS);
|
self._success(result.data);
|
self.fire(event.SUCCESS, {index:index, file:queue.getFile(index), result:result});
|
} else {
|
var msg = result.msg || result.message || EMPTY;
|
//修改队列中文件的状态为error(上传失败)
|
queue.fileStatus(index, Uploader.status.ERROR, {msg:msg, result:result});
|
self.fire(event.ERROR, {status:status, result:result, index:index, file:queue.getFile(index)});
|
}
|
//置空当前上传的文件在队列中的索引值
|
self.set('curUploadIndex', EMPTY);
|
self.fire(event.COMPLETE, {index:index, file:queue.getFile(index), result:result});
|
//存在批量上传操作,继续上传
|
self._continueUpload();
|
},
|
/**
|
* 取消上传后调用的方法
|
*/
|
_uploadStopHanlder:function () {
|
var self = this, queue = self.get('queue'),
|
index = self.get('curUploadIndex');
|
//更改取消上传后的状态
|
queue.fileStatus(index, Uploader.status.CANCEL);
|
//重置当前上传文件id
|
self.set('curUploadIndex', EMPTY);
|
self.fire(Uploader.event.CANCEL, {index:index});
|
},
|
/**
|
* 如果存在批量上传,则继续上传
|
*/
|
_continueUpload:function () {
|
var self = this,
|
uploadFilesStatus = self.get('uploadFilesStatus');
|
if (uploadFilesStatus != EMPTY) {
|
self._uploaderStatusFile(uploadFilesStatus);
|
}
|
},
|
/**
|
* 上传进度监听器
|
*/
|
_uploadProgressHandler:function (ev) {
|
var self = this, queue = self.get('queue'),
|
index = self.get('curUploadIndex'),
|
file = queue.getFile(index);
|
S.mix(ev, {file:file});
|
queue.fileStatus(index, Uploader.status.PROGRESS, ev);
|
self.fire(Uploader.event.PROGRESS, ev);
|
},
|
/**
|
* 上传成功后执行的回调函数
|
* @param {Object} data 服务器端返回的数据
|
*/
|
_success:function (data) {
|
if (!S.isObject(data)) return false;
|
var self = this, url = data.url,
|
urlsInput = self.get('urlsInput'),
|
fileIndex = self.get('curUploadIndex'),
|
queue = self.get('queue');
|
if (!S.isString(url) || !S.isObject(urlsInput)) return false;
|
//追加服务器端返回的文件url
|
queue.updateFile(fileIndex, {'sUrl':url});
|
//向路径隐藏域添加路径
|
urlsInput.add(url);
|
},
|
/**
|
* 添加默认数据到队列,不带参数的情况下,抓取restoreHook容器内的数据,添加到队列内
|
* @param {Array} data 文件数据
|
*/
|
restore:function (data) {
|
var self = this,
|
queue = self.get('queue'),
|
urlsInput = self.get('urlsInput');
|
if (!data) data = self._getRestoreData();
|
if (!data.length) return false;
|
|
S.each(data, function (file) {
|
//向队列添加文件
|
var fileData = queue.add(file);
|
var id = fileData.id;
|
var index = queue.getFileIndex(id);
|
//改变文件状态为成功
|
queue.fileStatus(index, 'success', {index:index, id:id, file:fileData});
|
});
|
},
|
/**
|
* 抓取restoreHook容器内的数据
|
* @return {Array}
|
*/
|
_getRestoreData:function () {
|
var self = this;
|
var urlsInput = self.get('urlsInput');
|
var urls = urlsInput.parse();
|
var files = [];
|
S.each(urls,function(url){
|
//伪造数据结构
|
files.push({
|
name:url,
|
type:'restore',
|
url : url,
|
sUrl : url,
|
result:{
|
status:1,
|
data:{
|
name:url,
|
url : url
|
}
|
}
|
});
|
});
|
return files;
|
}
|
}, {ATTRS:/** @lends Uploader.prototype*/{
|
/**
|
* Button按钮的实例
|
* @type Button
|
* @default {}
|
*/
|
button:{value:{}},
|
/**
|
* Queue队列的实例
|
* @type Queue
|
* @default {}
|
*/
|
queue:{value:{}},
|
/**
|
* 采用的上传方案,当值是数组时,比如“type” : ["flash","ajax","iframe"],按顺序获取浏览器支持的方式,该配置会优先使用flash上传方式,如果浏览器不支持flash,会降级为ajax,如果还不支持ajax,会降级为iframe;当值是字符串时,比如“type” : “ajax”,表示只使用ajax上传方式。这种方式比较极端,在不支持ajax上传方式的浏览器会不可用;当“type” : “auto”,auto是一种特例,等价于["ajax","flash","iframe"]。
|
* @type String|Array
|
* @default "auto"
|
* @since V1.2 (当“type” : “auto”,等价于["ajax","flash","iframe"])
|
*/
|
type:{value:Uploader.type.AUTO},
|
/**
|
* 是否开启多选支持,部分浏览器存在兼容性问题
|
* @type Boolean
|
* @default true
|
* @since V1.2
|
*/
|
multiple:{
|
value:true,
|
setter:function (v) {
|
var self = this, button = self.get('button');
|
if (!S.isEmptyObject(button) && S.isBoolean(v)) {
|
button.set('multiple', v);
|
}
|
return v;
|
}
|
},
|
/**
|
* 用于限制多选文件个数,值为负时不设置多选限制
|
* @type Number
|
* @default -1
|
* @since V1.2.6
|
*/
|
multipleLen:{ value:-1 },
|
/**
|
* 是否可用,false为可用
|
* @type Boolean
|
* @default false
|
* @since V1.2
|
*/
|
disabled:{
|
value:false,
|
setter:function (v) {
|
var self = this, button = self.get('button');
|
if (!S.isEmptyObject(button) && S.isBoolean(v)) {
|
button.set('disabled', v);
|
}
|
return v;
|
}
|
},
|
/**
|
* 服务器端配置。action:服务器处理上传的路径;data: post给服务器的参数,通常需要传递用户名、token等信息
|
* @type Object
|
* @default {action:EMPTY, data:{}, dataType:'json'}
|
*/
|
serverConfig:{value:{action:EMPTY, data:{}, dataType:'json'}},
|
/**
|
* 服务器处理上传的路径
|
* @type String
|
* @default ''
|
*/
|
action:{
|
value:EMPTY,
|
getter:function (v) {
|
return self.get('serverConfig').action;
|
},
|
setter:function (v) {
|
if (S.isString(v)) {
|
var self = this;
|
self.set('serverConfig', S.mix(self.get('serverConfig'), {action:v}));
|
}
|
return v;
|
}
|
},
|
/**
|
* 此配置用于动态修改post给服务器的数据,会覆盖serverConfig的data配置
|
* @type Object
|
* @default {}
|
* @since V1.2.6
|
*/
|
data:{
|
value:{},
|
getter:function () {
|
var self = this, uploadType = self.get('uploadType'),
|
data = self.get('serverConfig').data || {};
|
if (uploadType) {
|
data = uploadType.get('data');
|
}
|
return data;
|
},
|
setter:function (v) {
|
if (S.isObject(v)) {
|
var self = this, uploadType = self.get('uploadType');
|
if (S.isFunction(uploadType)) {
|
uploadType.set('data', v);
|
self.set('serverConfig', S.mix(self.get('serverConfig'), {data:v}));
|
}
|
}
|
return v;
|
}
|
},
|
/**
|
* 是否允许上传文件
|
* @type Boolean
|
* @default true
|
*/
|
isAllowUpload:{value:true},
|
/**
|
* 是否自动上传
|
* @type Boolean
|
* @default true
|
*/
|
autoUpload:{value:true},
|
/**
|
* 服务器端返回的数据的过滤器
|
* @type Function
|
* @default function(){}
|
*/
|
filter:{
|
value:EMPTY,
|
setter:function(v){
|
var self = this;
|
var uploadType = self.get('uploadType');
|
if(uploadType)uploadType.set('filter',v);
|
return v;
|
}
|
},
|
/**
|
* 存储文件路径的隐藏域的name名
|
* @type String
|
* @default ""
|
*/
|
urlsInputName:{value:EMPTY},
|
/**
|
* 当前上传的文件对应的在数组内的索引值,如果没有文件正在上传,值为空
|
* @type Number
|
* @default ""
|
*/
|
curUploadIndex:{value:EMPTY},
|
/**
|
* 上传方式实例
|
* @type UploaderType
|
* @default {}
|
*/
|
uploadType:{value:{}},
|
/**
|
* UrlsInput实例
|
* @type UrlsInput
|
* @default ""
|
*/
|
urlsInput:{value:EMPTY},
|
/**
|
* 存在批量上传文件时,指定的文件状态
|
* @type String
|
* @default ""
|
*/
|
uploadFilesStatus:{value:EMPTY},
|
/**
|
* 强制设置flash的尺寸,只有在flash上传方式中有效,比如{width:100,height:100},默认为自适应按钮容器尺寸
|
* @type Object
|
* @default {}
|
*/
|
swfSize:{value:{}}
|
}});
|
|
/**
|
* 转换文件大小字节数
|
* @param {Number} bytes 文件大小字节数
|
* @return {String} 文件大小
|
*/
|
S.convertByteSize = 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];
|
};
|
return Uploader;
|
}, {requires:['base', 'node', './urlsInput', './type/iframe', './type/ajax', './type/flash', './button/base', './button/swfButton', './queue']});
|