OpenAuth.Net/OpenAuth.Mvc/BJUI/js/bjui-upload.js

586 lines
26 KiB
JavaScript
Raw Normal View History

2015-11-13 21:33:53 +08:00
/*!
* B-JUI v1.2 (http://b-jui.com)
* Git@OSC (http://git.oschina.net/xknaan/B-JUI)
* Copyright 2014 K'naan (xknaan@163.com).
* Licensed under Apache (http://www.apache.org/licenses/LICENSE-2.0)
*/
/* ========================================================================
* B-JUI: bjui-upload.js v1.2
* @author K'naan (xknaan@163.com)
* -- Modified from Huploadify 2.0 (author:吕大豹)
* http://git.oschina.net/xknaan/B-JUI/blob/master/BJUI/js/bjui-upload.js
* ========================================================================
* Copyright 2014 K'naan.
* Licensed under Apache (http://www.apache.org/licenses/LICENSE-2.0)
* ======================================================================== */
+function ($) {
'use strict';
// UPLOAD CLASS DEFINITION
// ======================
var Upload = function(element, options) {
this.$element = $(element)
this.options = options
this.tools = this.TOOLS()
}
Upload.DEFAULTS = {
fileTypeExts : '*.jpg;*.png', //允许上传的文件类型,格式'*.jpg;*.doc'
uploader : '', //文件提交的地址
auto : false, //是否开启自动上传
method : 'POST', //发送请求的方式get或post
multi : false, //是否允许选择多个文件
formData : {}, //发送给服务端的参数,格式:{key1:value1,key2:value2}
fileObjName : 'file', //在后端接受文件的参数名称如PHP中的$_FILES['file']
fileSizeLimit : 204800, //允许上传的文件大小单位KB
previewImg : true, //是否预览上传图片
previewLoadimg : null, //预览图片前的载入图标
dragDrop : false, //是否允许拖动上传
showUploadedPercent : true, //是否实时显示上传的百分比如20%
showUploadedSize : true, //是否实时显示已上传的文件大小如1M/2M
buttonText : '选择上传文件', //上传按钮上的文字
removeTimeout : 1e3, //上传完成后进度条的消失时间
itemTemplate : FRAG.uploadTemp, //上传队列显示的模板
breakPoints : false, //是否开启断点续传
fileSplitSize : 1024 * 1024, //断点续传的文件块大小单位Byte默认1M
onUploadStart : null, //上传开始时的动作
onUploadSuccess : null, //上传成功的动作
onUploadComplete : null, //上传完成的动作
onUploadError : null, //上传失败的动作
onInit : null, //初始化时的动作
onCancel : null, //删除掉某个文件后的回调函数可传入参数file
onSelect : null
}
Upload.MIMETYPES = {
zip :[ 'application/x-zip-compressed' ],
jpg :[ 'image/jpeg' ],
png :[ 'image/png' ],
gif :[ 'image/gif' ],
swf :[ 'application/x-shockwave-flash' ],
doc :[ 'application/msword' ],
xls :[ 'application/vnd.ms-excel' ],
docx :[ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ],
xlsx :[ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ],
ppt :[ 'application/vnd.ms-powerpoint' ],
pptx :[ 'application/vnd.openxmlformats-officedocument.presentationml.presentation' ],
mp3 :[ 'audio/mpeg' ],
mp4 :[ 'video/mp4' ],
pdf :[ 'application/pdf' ],
txt :[ 'text/plain' ],
xml :[ 'text/xml' ]
}
Upload.prototype.TOOLS = function() {
var that = this, options = this.options
var tools = {
//将文件的单位由bytes转换为KB或MB若第二个参数指定为true则永远转换为KB
formatFileSize: function(size, byKB) {
if (size > 1024 * 1024 && !byKB)
size = (Math.round(size * 100 / (1024 * 1024)) / 100).toString() + 'MB'
else
size = (Math.round(size * 100 / 1024) / 100).toString() + 'KB'
return size
},
//根据文件序号获取文件
getFile: function(index, files) {
for (var i = 0; i < files.length; i++) {
if (files[i].index == index) return files[i]
}
return false
},
//将输入的文件类型字符串转化为数组,原格式为*.jpg;*.png
getFileTypes: function(str) {
var result = []
var arr1 = str.split(';')
for (var i = 0; i < arr1.length; i++) {
result.push(arr1[i].split('.').pop())
}
return result
},
//根据后缀名获得文件的mime类型
getMimetype: function(name) {
return Upload.MIMETYPES[name]
},
//根据配置的字符串获得上传组件accept的值
getAcceptString: function(str) {
var types = this.getFileTypes(str)
var result = []
for (var i = 0; i < types.length; i++) {
var mime = this.getMimetype(types[i])
if (mime) result.push(mime)
else result.push('.'+ types[i])
}
return result.join(',')
},
//过滤上传文件
filter: function(files) {
var arr = []
var typeArray = this.getFileTypes(options.fileTypeExts)
if (typeArray.length > 0) {
for (var i = 0; i < files.length; i++) {
var thisFile = files[i]
if (parseInt(this.formatFileSize(thisFile.size, true)) > options.fileSizeLimit) {
that.$element.alertmsg('error', '文件"'+ thisFile.name +'"大小超出限制!')
continue
}
if ($.inArray(thisFile.name.split('.').pop().toLowerCase(), typeArray) >= 0) {
arr.push(thisFile)
} else {
that.$element.alertmsg('error', '文件"'+ thisFile.name +'"类型不允许!')
}
}
}
return arr
},
//获取选择文件file控件
getFiles: function(e) {
var files = e.target.files || e.dataTransfer.files // 获取文件列表对象
files = this.filter(files)
for (var i = 0; i < files.length; i++) {
files[i].id = files[i].lastModifiedDate.getTime() +'_'+ files[i].size +'_'+ (files[i].type || '').replace(/\W/g, '')
this.renderQueueItem(files[i])
that.queueData.files++
}
return files
},
//生成上传队列Dom
renderQueueItem: function(file) {
var uploadedSize = 0
var $temp = $(options.itemTemplate
.replace('{fileId}', file.id)
.replace('{fileName}', file.name)
.replace('#upConfirm#', BJUI.regional.upload.upConfirm)
.replace('#upPause#', BJUI.regional.upload.upPause)
.replace('#upCancel#', BJUI.regional.upload.upCancel)
.replace('{percent}', '0.00%')
.replace('{uploadedSize}', '0KB')
.replace('{fileSize}', this.formatFileSize(file.size)))
//如果是自动上传,去掉上传按钮
if (options.auto) {
$temp.find('> .info > .up_confirm').remove()
}
$temp.data('upfile', file)
that.$uploadFileList.append($temp)
//如果断点续传
if (options.breakPoints) {
uploadedSize = this.getUploadedSize(file.id)
if (uploadedSize > file.size) uploadedSize = file.size
}
this.showProgress(file.id, uploadedSize, file.size)
//判断是否预览图片
if (options.previewImg && file.type.indexOf('image') != -1) {
var $prevbox = $temp.find('> .preview > .img')
if (options.previewLoadimg) $prevbox.html('<img src="'+ options.previewLoadimg +'" height="114">')
this.previewImg(file, $prevbox)
} else {
$temp.find('> .preview').remove()
}
//判断是否显示已上传文件大小
if (options.showUploadedSize) {
var $fileSize = $temp.find('> .filesize')
$fileSize.find('> .uploadedsize').html(this.formatFileSize(uploadedSize))
$fileSize.find('> .filesize').html(this.formatFileSize(file.size))
} else {
$temp.find('> .filesize').remove()
}
//判断是否显示上传百分比
if (options.showUploadedPercent) {
$temp.find('> .percent').html((uploadedSize / file.size * 100).toFixed(2) +'%')
} else {
$temp.find('> .percent').remove()
}
options.onSelect && options.onSelect(files)
//判断是否是自动上传
if (options.auto) that.fileUpload(file, uploadedSize)
$temp.on('click.bjui.upload.confirm', '.up_confirm', function(e) {
var $this = $(this), $queue = $this.closest('.item')
$this.hide().next().show()
that.fileUpload($queue.data('upfile'), uploadedSize)
})
$temp.on('click.bjui.upload.cancel', '.up_cancel', this.removeQueueItem)
},
successQueueItem: function(file, xhr) {
tools.showProgress(file.id, file.size, file.size)
options.onUploadSuccess && options.onUploadSuccess.toFunc().call(that, file, xhr.responseText, that.$element)
//在指定的间隔时间后删掉进度条
setTimeout(function() {
that.$element.find('#'+ file.id).fadeOut('normal', function() {
$(this).remove()
var filelen = that.$element.find('> .queue > .item:visible').length
if (filelen == 0) {
that.$element.find('> .queue').hide()
that.$file.val('')
}
})
}, options.removeTimeout)
},
removeQueueItem: function(e, xhr) {
if (xhr) xhr.abort()
$(this).closest('.item').fadeOut('normal', function() {
$(this).remove()
var filelen = that.$element.find('> .queue > .item:visible').length
if (filelen == 0) that.$element.find('> .queue').hide()
})
e.preventDefault()
},
//预览上传图片
previewImg: function(file, $obj) {
if (file && $obj.length) {
var reader = new FileReader()
reader.onload = function(e) {
$obj.html('<img src="'+ e.target.result +'">')
}
reader.readAsDataURL(file)
}
},
//上传进度条
showProgress: function(fileId, uploadedSize, fileSize) {
var initWidth = uploadedSize / fileSize * 100 +'%',
initFileSize = that.tools.formatFileSize(uploadedSize),
initUppercent = (uploadedSize / fileSize * 100).toFixed(2) +'%'
that.$element.find('#'+ fileId +' > .progress > .bar').css('width', initWidth)
},
//断点续传:获取已上传的文件片断大小
getUploadedSize: function(fileId) {
return localStorage.getItem(fileId) * 1
},
//断点续传:保存已上传的文件片断大小
saveUploadedSize:function(fileId, value) {
localStorage.setItem(fileId, value)
},
//发送文件块函数
sendBlob: function(url, xhr, file, formdata) {
var fd = new FormData()
xhr.open(options.method, url, true)
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
//xhr.setRequestHeader('X_Requested_With', location.href.split('/')[5].replace(/[^a-z]+/g, '$'))
fd.append(options.fileObjName, file)
if (formdata) {
for (var key in formdata) {
fd.append(key, formdata[key])
}
}
xhr.send(fd)
}
}
return tools
}
Upload.prototype.init = function() {
var that = this
var $element = this.$element
var options = this.options
if (!(options.uploader)) {
BJUI.debug('Upload Plugin: The options uploader is undefined!')
return
} else {
options.uploader = decodeURI(options.uploader).replacePlh($element.closest('.unitBox'))
if (!options.uploader.isFinishedTm()) {
$element.alertmsg('error', (options.warn || FRAG.alertPlhMsg.replace('#plhmsg#', BJUI.regional.plhmsg)))
BJUI.debug('Upload Plugin: The options uploader is incorrect: '+ options.uploader)
return
}
options.uploader = encodeURI(options.uploader)
}
if ($element.hasClass('bjui-upload')) return
var $uploadFrag = $(FRAG.uploadFrag
.replaceAll('#multi#', options.multi ? 'multiple' : '')
.replaceAll('#accept#', that.tools.getAcceptString(options.fileTypeExts))
.replaceAll('#btnTxt#', (options.icon ? '<i class="fa fa-'+ options.icon +'">&nbsp;&nbsp;' : '') + options.buttonText))
$element
.addClass('bjui-upload')
.append($uploadFrag)
this.$file = $element.find('> .bjui-upload-select-file')
this.$uploadFileList = $element.find('> .queue')
this.queueData = { files:0, success:0, error:0 }
//do select files
$element
.on('change.bjui.upload', '.bjui-upload-select-file', function(e) {
that.fileSelect(e)
})
.on('click.bjui.upload', '.bjui-upload-select', function(e) {
that.$file.trigger('click')
})
options.onInit && options.onInit()
//如果允许拖动上传
if (options.dragDrop) {
/* 拖拽元素在目标元素头上移动的时候 */
$element[0].ondragover = function(ev) {
ev.preventDefault()
return true
}
$element[0].ondrop = function(e) {
that.fileSelect(e)
e.stopPropagation()
e.preventDefault()
}
}
}
Upload.prototype.fileSelect = function(e) {
this.$uploadFileList.show()
this.tools.getFiles(e)
}
Upload.prototype.fileUpload = function(file, uploadedSize) {
var that = this, $element = that.$element, options = that.options, tools = that.tools
var xhr = false, originalFile = file
//校正进度条和上传比例的误差
xhr = new XMLHttpRequest()
if (options.breakPoints) {
//对文件进行切割,并保留原来的信息
file = originalFile.slice(uploadedSize, uploadedSize + options.fileSplitSize)
}
if (xhr.upload) {
// 上传进度
xhr.upload.onprogress = function(e) { that.onProgress(file, e.loaded, originalFile.size) }
// 上传回调
xhr.onreadystatechange = function(e) {
if (xhr.readyState == 4 && xhr.status == 200) {
var returnData = JSON.parse(xhr.responseText), upOver = false
if (options.breakPoints) {
//更新已上传文件大小,保存到本地
uploadedSize += options.fileSplitSize
tools.saveUploadedSize(originalFile.id, uploadedSize)
//继续上传其他片段
if (uploadedSize < originalFile.size) {
file = originalFile.slice(uploadedSize, uploadedSize + options.fileSplitSize)
//上传文件
tools.sendBlob(options.uploader, xhr, file, options.formData)
} else {
upOver = true
}
} else {
upOver = true
}
if (upOver) {
that.queueData.success++
tools.successQueueItem(originalFile, xhr)
options.onUploadComplete && options.onUploadComplete(originalFile, xhr.responseText)
}
} else {
that.queueData.error++
//错误回调
options.onUploadError && options.onUploadError(originalFile, xhr.responseText)
}
//队列完成回调
if (options.onQueueComplete) {
if (that.queueData.files = that.queueData.success + that.queueData.error)
option.onQueueComplete(that.queueData)
}
}
options.onUploadStart && options.onUploadStart()
//开始上传
options.formData.fileName = originalFile.name
options.formData.lastModifiedDate = originalFile.lastModifiedDate.getTime()
tools.sendBlob(options.uploader, xhr, file, options.formData)
}
//暂停事件
$element
.find('#'+ originalFile.id +' > .info > .up_pause')
.on('click.bjui.upload.pause', function(e) {
xhr.abort()
$(this).hide().prev().show()
})
//取消事件
$element
.find('#'+ originalFile.id +' > .info > .up_cancel')
.off('click.bjui.upload.cancel')
.on('click.bjui.upload.cancel', $.proxy(function(e) {
this.tools.removeQueueItem(e, xhr)
}, this))
}
Upload.prototype.onProgress = function(file, loaded, total) {
var that = this, options = that.options
var $progress = that.$element.find('#'+ file.id + ' .progress')
var thisLoaded = loaded
//根据上一次触发progress时上传的大小得到本次的增量
var lastLoaded = $progress.attr('lastLoaded') || 0
loaded -= parseInt(lastLoaded)
if (loaded > file.size) loaded = file.size
that.$progressBar = $progress.children('.bar')
var oldWidth = options.breakPoints ? parseFloat(that.$progressBar.get(0).style.width || 0) : 0
var percent = (loaded / total * 100 + oldWidth).toFixed(2)
var percentText = percent > 100 ? '100%' : percent + '%'
//校正四舍五入的计算误差
if (options.showUploadedSize) {
var $filesize = $progress.nextAll('.filesize')
$filesize.find('> .uploadedsize').text(that.tools.formatFileSize(loaded))
}
if (options.showUploadedPercent) {
$progress.nextAll('.up_percent').text(percentText)
}
that.$progressBar.css('width', percentText)
//记录本次触发progress时已上传的大小用来计算下次需增加的数量
if (thisLoaded < options.fileSplitSize) {
$progress.attr('lastLoaded', thisLoaded)
} else {
$progress.removeAttr('lastLoaded')
}
}
Upload.prototype.destroy = function() {
}
// UPLOAD PLUGIN DEFINITION
// =======================
function Plugin(option) {
var args = arguments
var property = option
if (window.FileReader) {
return this.each(function () {
var $this = $(this)
var options = $.extend({}, Upload.DEFAULTS, $this.data(), typeof option == 'object' && option)
var data = $this.data('bjui.upload')
if (!data) $this.data('bjui.upload', (data = new Upload(this, options)))
if (typeof property == 'string' && $.isFunction(data[property])) {
[].shift.apply(args)
if (!args) data[property]()
else data[property].apply(data, args)
} else {
data.init()
}
})
} else { //for IE8-9
this.each(function() {
if (!$.fn.uploadify) return
var options = {
swf : BJUI.PLUGINPATH +'uploadify/scripts/uploadify.swf',
fileTypeExts : '*.jpg;*.png',
id : 'fileInput',
fileObjName : 'file',
fileSizeLimit : 204800,
buttonText : '选择上传文件',
auto : false,
multi : false,
height : 24
}
var $element = $(this), op = $element.data()
if (!op.id) op.id = $element.attr('id')
$.extend(options, op)
if (!(options.uploader)) {
BJUI.debug('Upload Plugin: The options uploader is undefined!')
return
} else {
options.uploader = decodeURI(options.uploader).replacePlh($element.closest('.unitBox'))
if (!options.uploader.isFinishedTm()) {
$element.alertmsg('error', (options.warn || FRAG.alertPlhMsg.replace('#plhmsg#', BJUI.regional.plhmsg)))
BJUI.debug('Upload Plugin: The options uploader is incorrect: '+ options.uploader)
return
}
options.uploader = encodeURI(options.uploader)
}
if (options.id == 'fileInput') options.id = options.id + (new Date().getTime())
var $file = $('<input type="file" name="'+ options.name +'" id="'+ options.id +'">')
if (options.onInit && typeof options.onInit == 'string')
options.onInit = options.onInit.toFunc()
if (options.onCancel && typeof options.onCancel == 'string')
options.onCancel = options.onCancel.toFunc()
if (options.onSelect && typeof options.onSelect == 'string')
options.onSelect = options.onSelect.toFunc()
if (options.onUploadSuccess && typeof options.onUploadSuccess == 'string')
options.onUploadSuccess = options.onUploadSuccess.toFunc()
if (options.onUploadComplete && typeof options.onUploadComplete == 'string')
options.onUploadComplete = options.onUploadComplete.toFunc()
if (options.onUploadError && typeof options.onUploadError == 'string')
options.onUploadError = options.onUploadError.toFunc()
$file.appendTo($element)
if (!options.auto) {
var $upBtn = $('<button class="btn btn-orange" data-icon="cloud-upload">开始上传</button>')
$upBtn
.hide()
.insertAfter($element)
.click(function() {
$file.uploadify('upload', '*');
$(this).hide()
})
options.onSelect = function() {
$upBtn.show()
}
}
$file.uploadify(options)
})
}
}
var old = $.fn.upload
$.fn.upload = Plugin
$.fn.upload.Constructor = Upload
// UPLOAD NO CONFLICT
// =================
$.fn.upload.noConflict = function () {
$.fn.upload = old
return this
}
// UPLOAD DATA-API
// ==============
$(document).on(BJUI.eventType.initUI, function(e) {
var $this = $(e.target).find('[data-toggle="upload"]')
if (!$this.length) return
Plugin.call($this)
})
}(jQuery);