import Helper from './Upload/Helper'
import Request from './Upload/Request'
import Input from './Upload/Input'
import Status from './Upload/Status'
import AddFile from './Upload/AddFile'
import AddUploadedFile from './Upload/AddUploadedFile'
/**
* WebUploader 上传组件
*
* @see http://fex.baidu.com/webuploader/
*/
(function (w, $) {
let Dcat = w.Dcat;
class Uploader {
constructor(options) {
this.options = options = $.extend({
wrapper: '.web-uploader', // 图片显示容器选择器
addFileButton: '.add-file-button', // 继续添加按钮选择器
inputSelector: '',
isImage: false,
preview: [], // 数据预览
server: '',
updateServer: '',
autoUpload: false,
sortable: false,
deleteUrl: '',
deleteData: {},
thumbHeight: 160,
elementName: '',
disabled: false, // 禁止任何上传编辑
autoUpdateColumn: false,
removable: false, // 是否允许直接删除服务器图片
downloadable: false, // 是否允许下载文件
dimensions: {
// width: 100, // 图片宽限制
// height: 100, // 图片高限制
// min_width: 100, //
// min_height: 100,
// max_width: 100,
// max_height: 100,
// ratio: 3/2, // 宽高比
},
lang: {
exceed_size: '文件大小超出',
interrupt: '上传暂停',
upload_failed: '上传失败,请重试',
selected_files: '选中:num个文件,共:size。',
selected_has_failed: '已成功上传:success个文件,:fail个文件上传失败,重新上传失败文件或忽略',
selected_success: '共:num个(:size),已上传:success个。',
dot: ',',
failed_num: '失败:fail个。',
pause_upload: '暂停上传',
go_on_upload: '继续上传',
start_upload: '开始上传',
upload_success_message: '已成功上传:success个文件',
go_on_add: '继续添加',
Q_TYPE_DENIED: '对不起,不允许上传此类型文件',
Q_EXCEED_NUM_LIMIT: '对不起,已超出文件上传数量限制,最多只能上传:num个文件',
F_EXCEED_SIZE: '对不起,当前选择的文件过大',
Q_EXCEED_SIZE_LIMIT: '对不起,已超出文件大小限制',
F_DUPLICATE: '文件重复',
confirm_delete_file: '您确定要删除这个文件吗?',
},
upload: { // web-uploader配置
formData: {
_id: null, // 唯一id
},
thumb: {
width: 160,
height: 160,
quality: 70,
allowMagnify: true,
crop: true,
preserveHeaders: false,
// 为空的话则保留原有图片格式。
// 否则强制转换成指定的类型。
// IE 8下面 base64 大小不能超过 32K 否则预览失败,而非 jpeg 编码的图片很可
// 能会超过 32k, 所以这里设置成预览的时候都是 image/jpeg
type: 'image/jpeg'
},
}
}, options);
let _this = this;
// WebUploader
// @see http://fex.baidu.com/webuploader/
_this.uploader = WebUploader.create(options.upload);
_this.$selector = $(options.selector);
_this.updateColumn = options.upload.formData.upload_column || ('webup' + Dcat.helpers.random());
_this.relation = options.upload.formData._relation; // 一对多关联关系名称
// 帮助函数
let helper = new Helper(this),
// 请求处理
request = new Request(this),
// 状态管理
status = new Status(this),
// 添加文件
addFile = new AddFile(this),
// 添加已上传文件
addUploadedFile = new AddUploadedFile(this),
// 表单
input = new Input(this);
_this.helper = helper;
_this.request = request;
_this.status = status;
_this.addFile = addFile;
_this.addUploadedFile = addUploadedFile;
_this.input = input;
// 翻译
_this.lang = Dcat.Translator(options.lang);
// 所有文件的进度信息,key为file id
_this.percentages = {};
// 临时存储上传失败的文件,key为file id
_this.faildFiles = {};
// 临时存储添加到form表单的文件
_this.formFiles = {};
// 添加的文件数量
_this.fileCount = 0;
// 添加的文件总大小
_this.fileSize = 0;
if (typeof options.upload.formData._id === "undefined" || ! options.upload.formData._id) {
options.upload.formData._id = _this.updateColumn + Dcat.helpers.random();
}
}
// 初始化
build() {
let _this = this,
uploader = _this.uploader,
options = _this.options,
$wrap = _this.$selector.find(options.wrapper),
// 图片容器
$queue = $('
').appendTo($wrap.find('.queueList')),
// 状态栏,包括进度和控制按钮
$statusBar = $wrap.find('.statusBar'),
// 文件总体选择信息。
$info = $statusBar.find('.info'),
// 上传按钮
$upload = $wrap.find('.upload-btn'),
// 没选择文件之前的内容。
$placeholder = $wrap.find('.placeholder'),
$progress = $statusBar.find('.upload-progress').hide();
// jq选择器
_this.$wrapper = $wrap;
_this.$files = $queue;
_this.$statusBar = $statusBar;
_this.$uploadButton = $upload;
_this.$placeholder = $placeholder;
_this.$progress = $progress;
_this.$infoBox = $info;
if (options.upload.fileNumLimit > 1 && ! options.disabled) {
// 添加“添加文件”的按钮,
uploader.addButton({
id: options.addFileButton,
label: ' ' + _this.lang.trans('go_on_add')
});
}
// 拖拽时不接受 js, txt 文件。
_this.uploader.on('dndAccept', function (items) {
var denied = false,
len = items.length,
i = 0,
// 修改js类型
unAllowed = 'text/plain;application/javascript ';
for (; i < len; i++) {
// 如果在列表里面
if (~unAllowed.indexOf(items[i].type)) {
denied = true;
break;
}
}
return !denied;
});
// 进度条更新
uploader.onUploadProgress = function (file, percentage) {
_this.percentages[file.id][1] = percentage;
_this.status.updateProgress();
};
// uploader.onBeforeFileQueued = function (file) {};
// 添加文件
uploader.onFileQueued = function (file) {
_this.fileCount++;
_this.fileSize += file.size;
if (_this.fileCount === 1) {
// 隐藏 placeholder
$placeholder.addClass('element-invisible');
$statusBar.show();
}
// 添加文件
_this.addFile.render(file);
_this.status.switch('ready');
// 更新进度条
_this.status.updateProgress();
if (!options.disabled && options.autoUpload) {
// 自动上传
uploader.upload()
}
};
// 删除文件事件监听
uploader.onFileDequeued = function (file) {
_this.fileCount--;
_this.fileSize -= file.size;
if (! _this.fileCount && !Dcat.helpers.len(_this.formFiles)) {
_this.status.switch('pending');
}
_this.removeUploadFile(file);
};
uploader.on('all', function (type, obj, reason) {
switch (type) {
case 'uploadFinished':
_this.status.switch('confirm');
// 保存已上传的文件名到服务器
_this.request.update();
break;
case 'startUpload':
_this.status.switch('uploading');
break;
case 'stopUpload':
_this.status.switch('paused');
break;
case 'uploadAccept':
if (_this._uploadAccept(obj, reason) === false) {
return false;
}
break;
}
});
uploader.onError = function (code) {
switch (code) {
case 'Q_TYPE_DENIED':
Dcat.error(_this.lang.trans('Q_TYPE_DENIED'));
break;
case 'Q_EXCEED_NUM_LIMIT':
Dcat.error(_this.lang.trans('Q_EXCEED_NUM_LIMIT', {num: options.upload.fileNumLimit}));
break;
case 'F_EXCEED_SIZE':
Dcat.error(_this.lang.trans('F_EXCEED_SIZE'));
break;
case 'Q_EXCEED_SIZE_LIMIT':
Dcat.error(_this.lang.trans('Q_EXCEED_SIZE_LIMIT'));
break;
case 'F_DUPLICATE':
Dcat.warning(_this.lang.trans('F_DUPLICATE'));
break;
default:
Dcat.error('Error: ' + code);
}
};
// 上传按钮点击
$upload.on('click', function () {
let state = _this.status.state;
if ($(this).hasClass('disabled')) {
return false;
}
if (state === 'ready') {
uploader.upload();
} else if (state === 'paused') {
uploader.upload();
} else if (state === 'uploading') {
uploader.stop();
}
});
// 重试按钮
$info.on('click', '.retry', function () {
uploader.retry();
});
// 忽略按钮
$info.on('click', '.ignore', function () {
for (let i in _this.faildFiles) {
uploader.removeFile(i, true);
delete _this.faildFiles[i];
}
});
// 初始化
_this.status.switch('init');
}
_uploadAccept(obj, reason) {
let _this = this,
options = _this.options;
// 上传失败,返回false
if (! reason || ! reason.status) {
_this.helper.showError(reason);
_this.faildFiles[obj.file.id] = obj.file;
return false;
}
if (reason.data && reason.data.merge) {
// 分片上传
return;
}
// 上传成功,保存新文件名和路径到file对象
obj.file.serverId = reason.data.id;
obj.file.serverName = reason.data.name;
obj.file.serverPath = reason.data.path;
obj.file.serverUrl = reason.data.url || null;
_this.addUploadedFile.add(obj.file);
_this.input.add(reason.data.id);
let $li = _this.getFileView(obj.file.id);
if (! _this.isImage()) {
$li.find('.file-action').hide();
$li.find('[data-file-act="delete"]').show();
}
if (options.sortable) {
$li.find('[data-file-act="order"]').removeClass('d-none').show();
}
if (options.downloadable) {
let $download = $li.find('[data-file-act="download"]');
$download.removeClass('d-none').show();
$download.attr('data-id', obj.file.serverUrl);
}
}
// 预览
preview() {
let _this = this,
options = _this.options,
i;
for (i in options.preview) {
let path = options.preview[i].path, ext;
if (path.indexOf('.')) {
ext = path.split('.').pop();
}
let file = {
serverId: options.preview[i].id,
serverUrl: options.preview[i].url,
serverPath: path,
ext: ext,
fake: 1,
};
_this.status.switch('incrOriginalFileNum');
_this.status.switch('decrFileNumLimit');
// 添加文件到预览区域
_this.addUploadedFile.render(file);
_this.addUploadedFile.add(file);
}
}
// 重新渲染已上传文件
reRenderUploadedFiles() {
let _this = this;
_this.$files.html('');
_this.addUploadedFile.reRender();
}
// 重置按钮位置
refreshButton() {
this.uploader.refresh();
}
// 获取文件视图选择器
getFileViewSelector(fileId) {
return this.options.elementName.replace(/[\[\]]*/g, '_') + '-' + fileId;
}
getFileView(fileId) {
return $('#' + this.getFileViewSelector(fileId));
}
// 负责view的销毁
removeUploadFile(file) {
let _this = this,
$li = _this.getFileView(file.id);
delete _this.percentages[file.id];
_this.status.updateProgress();
$li.off().find('.file-panel').off().end().remove();
}
// 上传字段名称
getColumn() {
return this.updateColumn
}
// 判断是否是图片上传
isImage() {
return this.options.isImage
}
}
Dcat.Uploader = function (options) {
return new Uploader(options)
};
})(window, jQuery);