(function ($) {
/**
* 多文件上传控件,用于上传文件的控件,支持多文件,格式限制,图片预览,文件大小限制等功能。
*
* @example
* var file = new FR.MultiFileEditor({
* renderEl : 'body'
* });
*
* @class FR.MultiFileEditor
* @extends FR.BaseEditor
*
* @cfg {JSON} options 属性配置
* @cfg {Number} [options.width=120] 宽度
* @cfg {Number} [options.height=20] 高度
* @cfg {Boolean} [options.render=true] 是否渲染
* @cfg {Boolean} [options.showViewImage=true] 编辑完显示预览图片
*/
FR.MultiFileEditor = FR.extend(FR.BaseEditor, /**@class FR.MultiFileEditor*/{
/**
* @returns {*}
* @private
*/
_defaultConfig: function () {
return $.extend(FR.MultiFileEditor.superclass._defaultConfig.apply(), {
width: 120, // 预览面板的宽度
height: 20, // 预览面板的高度
render: true,
// 编辑完显示预览图片
showViewImage: true
});
},
/**
* @private
*/
_init: function () {
FR.$defaultImport('/com/fr/web/core/js/noswfupload.js', 'js');
FR.$defaultImport('/com/fr/web/core/css/widget/noswfupload-icons.css',
'css');
FR.MultiFileEditor.superclass._init.apply(this, arguments);
var o = this.options;
var self = this;
this.$uploadForm = $('<form enctype="multipart/form-data"></form>')
.css('position', 'relative').appendTo(this.element);
this.divWrap = $("<div></div>").css({
'width': this.options.width + 'px',
'height': this.options.height + 'px',
'position': 'relative',
'overflow': 'hidden'
}).appendTo(this.$uploadForm);
this.$fileupload = $('<input type="file" name="file"/>')
.addClass('fr-fileupload').appendTo(this.divWrap);
// be sure input accept multiple files
if (o.maxlength !== 1) {
this.$fileupload[0].setAttribute("multiple", "multiple");
}
if (o.disabled) {
this.$fileupload[0].setAttribute("disabled", "disabled");
}
// 添加预览面板
if (o.render === true) {
var min = Math.min(this.options.height, this.options.width);
var pImageSize = min > 32 ? 32 : min - 2;
var pCountSize = min > 32 ? 20 : min * 0.7;
this.$previewImage = $("<img>").attr("src", FR.servletURL + "?op=resource&resource=/com/fr/web/images/file/upload.gif")
.appendTo(this.divWrap).addClass("fr-fileupload-image")
.css({
left: this.options.width > 32 ?
(this.options.width - 32) / 2 : 0,
top: this.options.height > 32 ?
(this.options.height - 32) / 2 : 0,
width: pImageSize,
height: pImageSize
});
if (o.tooltipText) {
var toolSpan = $("<span/>").addClass("fr-fileupload-tooltipspan");
this.tooltipDiv = $("<div/>").css({
left: pImageSize + 7 + 'px',
height: pImageSize + 'px'
}).append(toolSpan.text(o.tooltipText)).addClass("fr-fileupload-tooltip").appendTo(this.$uploadForm);
}
this.$preview = this.$previewImage;
if (self.options.maxlength !== 1) {
this.$previewCount = $('<div class="fr-fileupload-preview-count"/>').text(0)
.appendTo(this.divWrap).css({
left: this.options.width > 32 ?
(this.options.width - 32) / 2 + 22 : this.$previewImage.width() - 10,
top: this.options.height > 32 ?
(this.options.height - 32) / 2 + 8 : 0,
width: pCountSize,
height: pCountSize,
'border-radius': pCountSize,
'font-size': pCountSize * 0.6
});
}
} else {
this.$preview = this.element;
}
if (this.options.write) {
$('.fr-fileupload', self.element).css({
'right': 0,
'font-size': self.element.height() < 100
? '100px'
: self.element.height() + 'px',
'width': this.options.width,
'height': this.options.height
});
}
// create the noswfupload.wrap Object
// wrap.maxSize 文件大小限制
// wrap.maxlength 文件个数限制
this.wrap = noswfupload.wrap((this.$fileupload)[0], o.maxSize, o.maxlength,
this.options.width, this.options.height);
var wrap = this.wrap;
// fileType could contain whatever text but filter checks *.{extension}
// if present
// handlers
wrap.onerror = function () {
noswfupload.text(this.dom.info, "WARNING: Unable to upload "
+ this.file.fileName);
};
wrap.onloadstart = function (rpe, xhr) {
this.show(0, 0);
noswfupload.text(this.dom.info, "Preparing for upload ... ");
};
wrap.onprogress = function (rpe, xhr) {
// percent for each bar
this.show((this.sent + rpe.loaded) * 100 / this.total, rpe.loaded * 100 / rpe.total);
noswfupload.text(this.dom.info, FR.i18nText("FR-Basic-File_Uping_File") + ": " + this.file.fileName);
// fileSize is -1 only if browser does not support file info access
// this if splits recent browsers from others
if (this.file.fileSize !== -1) {
// simulation property indicates when the progress event is fake
if (rpe.simulation) {
noswfupload.text(this.dom.info,
FR.i18nText("FR-Basic-File_Uping_File") + ": " + this.file.fileName,
FR.i18nText("FR-Basic-File_All_File_Uploaded") + noswfupload.size(this.sent + rpe.loaded));
} else {
noswfupload.text(this.dom.info,
FR.i18nText("FR-Basic-File_Uping_File") + ": " + this.file.fileName,
FR.i18nText("FR-Basic-File_Uploaded_File") + ": " + noswfupload.size(rpe.loaded),
FR.i18nText("FR-Basic-File_All_File_Uploaded") + noswfupload.size(this.sent + rpe.loaded));
}
} else {
// if fileSIze is -1 browser is using an iframe because it does
// not support
// files sent via Ajax (XMLHttpRequest)
// We can still show some information
noswfupload.text(this.dom.info,
"Uploading: " + this.file.fileName,
"Sent: " + (this.sent / 100) + " out of " + (this.total / 100));
}
};
// generated if there is something wrong during upload
wrap.onerror = function () {
// just inform the user something was wrong
noswfupload.text(this.dom.info, "WARNING: Unable to upload "
+ this.file.fileName);
};
// generated when every file has been sent (one or more, it does not
// matter)
wrap.onload = function (rpe, xhr) {
var self_ = this;
// just show everything is fine ...
noswfupload.text(this.dom.info, "Upload complete");
// ... and after a second reset the component
setTimeout(function () {
self_.clean(); // remove files from list
self_.hide(); // hide progress bars and enable input file
noswfupload.text(self_.dom.info, "");
self.fireEvent(FR.Events.AFTEREDIT);
// enable again the submit button/element
}, 1000);
self.showViewList();
var attach =self.wrap.attach_array[0];
self.fireEvent(FR.Events.CALLBACK, attach);
// fileListWrap.parent().css("overflow", "auto");
};
wrap.url = this.options.url ? this.options.url : FR.servletURL
+ '?op=fr_attach&cmd=ah_upload';
//传到不同的服务器上, 会导致httpsession相互覆盖, 处理起来更麻烦了
wrap.url += ((window.FS && window.FS.serverID) ? '&serverID='+ window.FS.serverID : "");
wrap.fileType = o.accept; //文件类型限制
wrap.attach_array = [];
wrap.attach_names = [];
wrap.attachNum = 0;
this._dealValueWithEvents(o.value);
},
/**
* @param {JSON} attach 文件对象
* @private
*/
_dealValueWithEvents: function (attach) {
if (FR.equals(attach, this.wrap.attach_array)
|| (this.wrap.attach_array.length === 1 && FR.equals(
this.wrap.attach_array[0], attach))) {
return;
}
if (($.isArray(attach) && attach.length > 0 && attach[0].attach_id)
|| (attach && attach.attach_id)) {
var attach_array = $.isArray(attach) ? attach : [attach];
this.wrap.attach_array = [];
for (var i = 0; i < attach_array.length; i++) {
// 编辑前setValue4Write(),不能让oldvalue跟getValue是同一个对象
this.wrap.attach_array.push(attach_array[i]);
var obj = {};
this.wrap.files.push(obj);
}
this.showViewList();
this.wrap.files.length = 0;
}
// 按delete或者backspace时候
if (attach == '') {
this.reset();
}
},
/**
* 生成上传文件列表
* @param {JSON} attach 上传的文件信息对象
* @param {Number} i 位置索引
* @returns {jQuery} 返回生成的列表DOM
*/
createListItem: function (attach, i) {
var self = this;
var download = $("<li></li>");
var cancelButton;
download
.append(cancelButton = ($("<a class='fr-fileupload-progressCancel' href='#'> </a>"))
.click(function (e) {
self.removeAttach(attach, download);
e.stopEvent();
}).hide())
.append($("<span class='fr-fileupload-fileNameItem'>"
+ self.wrap.attach_names[i] + " "
+ FR.__fileSizeFormat__(attach.fileSize) + "</span>")
.bind("click", function () {
var attach_id = attach.attach_id;
window.open(FR.servletURL
+ "?op=fr_attach&cmd=ah_download&id="
+ attach_id);
})
.mouseover(function () {
$(this).css({color: 'blue' })
})
.mouseout(function () {
$(this).css({color: '' })
})).addClass("fr-fileupload-listitem").mouseover(
function () {
cancelButton.show();
$(this).css({'background-color': '#9FC5F8'})
}).mouseout(function () {
cancelButton.hide();
$(this).css({'background-color': ''})
});
self.wrap.attachNum++;
if (self.wrap.maxlength !== 1) {
self.$previewCount.text(self.wrap.attachNum);
}
return download;
},
/**
* 显示文件列表
*/
showViewList: function () {
var self = this;
var fileListDiv;
var fileListWrap;
if (!self.options.hideFileList) {
var fileListUl = $("ul", self.element);
if (fileListUl.length === 0) {
var contentDiv = $("<div class='fr-fileupload-popview'/>").appendTo(self.element).css({
marginTop: 18 - self.options.height / 2,
marginLeft : self.options.width / 2 + 18
});
fileListDiv = $("<div class='fr-fileupload-popview-list'/>").appendTo(contentDiv);
fileListWrap = $("<ul/>").addClass("fr-fileupload-list").appendTo(fileListDiv);
} else {
fileListDiv = fileListUl.parent();
fileListWrap = fileListUl;
}
}
var wrap = self.wrap;
this.imageURL = null;
if (self.options.maxlength === 1) {
var o = this.options;
var attach = wrap.attach_array[0];
this.removeBackground();
if (attach.attach_type == 'image') {
self.$tempPreview =
$("<td></td>")
.appendTo(this.divWrap).css({
left: self.element.outerWidth(true) - self.element.width(),
width: o.width,
height: o.height,
top: 0,
position: 'absolute'
});
FR.lastTarget = self.$tempPreview;
var $target = $(self.$tempPreview);
$target.css("background", "");
var im_url = FR.servletURL + '?op=fr_attach&cmd=ah_image&id='
+ attach.attach_id;
$target.css('background', 'url(' + im_url + ") 0 0 no-repeat transparent");
this.imageURL = im_url;
$target.css("cursor", "default").unbind("click", download)
}
wrap.attach_names[0] = attach.filename;
if (fileListWrap) {
fileListWrap.children().remove();
fileListWrap.append(this.createListItem(attach, 0));
}
}
// 多文件时要处理重名的问题
if (self.options.maxlength !== 1) {
for (var i = wrap.attach_array.length - 1, m = 0; m < wrap.files.length; i--, m++) {
wrap.attach_names[i] = wrap.attach_array[i].filename;
var dup = 0;
for (var j = 0; j < wrap.attach_array.length - wrap.files.length; j++) {
if (wrap.attach_names[i] === wrap.attach_array[j].filename) {
dup++;
}
}
if (dup > 0) {
wrap.attach_names[i] = FR.lengthenFileName(wrap.attach_array[i].filename, "(" + dup + ")");
}
fileListWrap && fileListWrap.append(this.createListItem(wrap.attach_array[i], i));
}
}
// ie杂项不支持max-height属性
if (FR.Browser.isIE() && fileListDiv) {
if (fileListDiv.height() > 160) {
fileListDiv.height(160);
if (fileListWrap.width() + 18 > fileListDiv.width()) {
fileListDiv.width(fileListWrap.width() + 18);
}
}
}
function download(e) {
window.open(FR.servletURL + "?op=fr_attach&cmd=ah_download&id="
+ e.data);
e.stopPropagation();
}
},
/**
* 移除已上传的文件
* @param {JSON} attach 上传的文件对象
* @param {jQuery} download 文件显示所在的DOM对象
*/
removeAttach: function (attach, download) {
var attach_id = attach.attach_id;
var self = this;
var wrap = this.wrap;
FR.ajax({
url: FR.servletURL + "?op=fr_attach&cmd=ah_release",
data: {
id: attach_id
},
complete: function (res, status) {
if (status == 'success') {
if (download) {
download.remove();
}
for (var n = 0; n < wrap.attach_array.length; n++) {
if (wrap.attach_array[n].attach_id == attach_id) {
if (self.wrap.maxlength !== 1) {
wrap.attachNum--;
self.$previewCount.text(self.wrap.attachNum);
if (wrap.attachNum === 0) {
$(".fr-fileupload-popview", self.element).remove();
}
}
wrap.attach_array.remove(wrap.attach_array[n]);
break;
}
}
if (self.wrap.maxlength === 1) {
$(".fr-fileupload-popview", self.element).remove();
self.removeBackground();
}
self.fireEvent(FR.Events.CALLBACK);
}
}
})
},
/**
* 重置背景图片
* 格子的高度可能发生了改变 要调整
* @param u
*/
resetBackground: function(u) {
var url = u || this.imageURL;
this.removeBackground();
if (this.options.tdCell) {
this.options.tdCell.css('background', 'url(' + url
+ "&height=" + this.options.tdCell.height() + ") 0 0 no-repeat transparent");
}
},
/**
* 特指移除单文件上传中添加图片后的背景
*/
removeBackground: function () {
// 这个background是指单文件添加了图片的情况
// 有两处需要移除 一个原始报表结构的td中 一个是动态生成的x-editor中
// 还有可能用在表单啊
if (this.options.tdCell) {
this.options.tdCell.css('background-image', '');
}
var previousAtt = this.divWrap.children().eq(2);
previousAtt.css('background-image', '');
previousAtt.remove();
},
startEditing: function () {
if (this.options.tdCell) {
$('.attach-download-div,.fr-fileupload-download-all', $(this.options.tdCell)).hide();
}
this.$preview.show();
// richer:文件的enable需要单独处理
if (this.options.disabled) {
this.$preview.unbind("click");
}
// IE杂项模式 x-editor的高度总是比文件控件高一些 导致浅蓝色边框超出
// 没搞懂为什么变大 索性去掉这个控件编辑的浅蓝框子
if (FR.Browser.isIE() && !$.support.boxModel && this.options.write) {
$(".x-editor").addClass('none-border');
}
},
stopEditing: function () {
if (this.options.tdCell) {
var cur = $('.attach-download-div,.fr-fileupload-download-all', $(this.options.tdCell));
cur.show();
}
if (FR.Browser.isIE() && !$.support.boxModel && this.options.write) {
$(".x-editor").removeClass('none-border');
}
if (this.imageURL != null) {
var self = this;
setTimeout(function() {
self.resetBackground();
}, 200);
}
},
getValue: function () {
if (!this.wrap.attach_array) {
//return [];
// shoc: 返回空数组有个问题,提交入库的时候空文件控件值到后台变成"[]"始终会入库一条记录,
// 后台拦截了null、""等情况,在那里判断拦截这个不太合适,还是改这里了
return "";
}
if (this.options.maxlength === 1 && this.wrap.attach_array[0]
&& this.wrap.attach_array[0].attach_type == "image") {
return this.wrap.attach_array[0];
}
return this.wrap.attach_array.length === 0 ? "" : this.wrap.attach_array;
},
setEnable: function (enable) {
FR.MultiFileEditor.superclass.setEnable.apply(this, arguments);
if (this.$fileupload && this.$fileupload[0]) {
if (enable) {
this.$fileupload[0].removeAttribute("disabled");
} else {
this.$fileupload[0].setAttribute("disabled", "disabled");
}
}
},
/**
* 是否显示预览图片
* @returns {Boolean} 返回是否显示预览图片
*/
isShowViewImage: function () {
return this.options.showViewImage && this.options.maxlength === 1;
},
reset: function () {
this.wrap.attach_array = [];
this.wrap.attach_names = [];
this.wrap.attachNum = 0;
if (this.options.tdCell) {
$('.attach-download-div', $(this.options.tdCell)).remove();
}
$('.fr-fileupload-popview', this.element).remove();
this.removeBackground();
}
});
$.shortcut("multifile", FR.MultiFileEditor);
})(jQuery);