OpenAuth.Net/OpenAuth.Mvc/BJUI/js/bjui-upload.js
2015-11-13 21:33:53 +08:00

586 lines
26 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* 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);