s94-file
Version:
浏览器中,用于文件上传和在线文件选择的可视化插件
337 lines (332 loc) • 13.9 kB
JavaScript
(function($){
"use strict";
var __DIR__= $.dirname(module.filename),rem,
boxdom, boxid='s94_file'+(new Date()).getTime(),
$menu,$tabs,$num,$input_file,
setup = {},
dir_stack=[''],
mime_map={
'jpg':'image/jpeg','jpeg':'image/jpeg','png':'image/png','gif':'image/gif','ico':'image/x-icon','webp':'image/webp','bmp':'image/bmp',
'mp4':'video/mp4','avi':'video/avi','wmv':'video/x-ms-wmv',
'mp3':'audio/mp3','aif':'audio/aiff','aiff':'audio/aiff','wav':'audio/wav','wma':'audio/x-ms-wma','m4a':'audio/x-m4a',
'txt':'text/plain','js':'application/javascript,text/javascript','css':'text/css','xml':'text/xml','jsp':'text/html','html':'text/html','htm':'text/html','asp':'text/asp',
'ppt':'application/vnd.ms-powerpoint','pptx':'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'xls':'application/vnd.ms-excel','xlsx':'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'doc':'application/msword','pdf':'application/pdf','docx':'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
},
STR = {
'ajax_error': '网络异常,请稍后再试',
'select_error': '最多只能选择一个文件!',
'no_url': 'upload_url和filelist_url至少配置一个!',
'this_dir': '当前路径:/',
'upload': '本地上传',
'online': '在线管理',
'ok': '确定',
'cancel': '取消',
'select': '点击选择文件',
};
//工具函数
var tips = $.msg.tips;
function ajax(op){
op.global = false;
op.type = "post";
$.ajax(op);
}
function file_type(name){
try{
return name.match(/\.(\w+)$/)[1];
}catch(e){
return '';
}
}
function is_img(type){ return ['jpg','jpeg','png','gif'].indexOf(type) !== -1; }
function img_src(value){ return !/^https?:\/\//.test(value) && setup.host ? '//'+setup.host+value : value; }
function file_html(op){
op.type = op.type || file_type(op.url);
op.index = op.index || '';
var imgsrc = is_img(op.type) ? img_src(op.url) : __DIR__+'/image/type/'+op.type+'.png';
var html = '<li file '+(op.checked?'class="checked"':'')+' index="'+op.index+'" title="'+op.url+'" file_url="'+op.url+'" >';
html+='<img onerror="'+boxid+'_imger(this)" type="'+op.type+'" src="'+imgsrc+'">';
html+=(op.marsk?'<b></b>':'')+'<i onclick="'+boxid+'_select(this)"><span>'+op.index+'</span></i></li>';
return html;
}
//请求获取文件列表
function get_manage(dir){
if(!setup.filelist_url) return false;
var data = {accept: setup.accept};
if (dir) data['dir'] = dir;
ajax({
url: setup.filelist_url,
data: data,
success: function(res){
get_manage.files = res.data.files;
$tabs.eq(1).find('ul li').remove();
var html = '<li dir><span style="font-size: 0.16em;">'+STR['this_dir']+(dir||'')+'</span></li>'
if (dir_stack.length > 1) {//是否存在上级目录
html += '<li dir onclick="'+boxid+'_dir(this)" dir_name="../"><span>../</span></li>';
}
for(var i=0;i<res.data.dirs.length;i++){
var name = $.trim(res.data.dirs[i],'/').split('/').pop();
html += '<li dir onclick="'+boxid+'_dir(this)" dir_name="'+res.data.dirs[i]+'"><span>'+name+'</span></li>';
}
$tabs.eq(1).find('ul>p').before(html);
get_manage.index = 0;
get_manage.over = false;
get_manage.loop();
},
error: function(res){ tips(res.message) }
})
}
get_manage.loop = function(){
if(get_manage.over) return;
var $p = $tabs.eq(1).find('ul>p');
var dty = $p.domOffsetParent()['y'];
if(dty > 4*rem) return;
var i = get_manage.index || 0;
var end = i+5;
if(end >= get_manage.files.length){
end = get_manage.files.length;
get_manage.over = true;
}
for (var html=''; i < end; i++) {
html += file_html({url: get_manage.files[i]});
}
get_manage.index = i;
$p.before(html);
get_manage.loop();
}
function init(){
if(boxdom) return;
boxdom = document.createElement('div');
var html='';
html+='<style type="text/css">';
html+='#'+boxid+'{position: fixed;color:#333;left: 0;top: 0;width: 100%;height: 100%;z-index: 999999;background: rgba(0,0,0,.5);display: flex;justify-content: center;align-items: center;}';
html+='#'+boxid+' *{box-sizing:border-box;margin: 0;padding: 0;list-style-type: none;}';
html+='#'+boxid+' span{font-size: 0.2em;line-height:1;}';
html+='#'+boxid+'>dl{display: flex;flex-direction: column;position: relative;width: 6.4em;height: 4.5em;background: #fff;}';
html+='#'+boxid+'>dl>ol{height: 0.6em;padding: 0.1em;display: flex;border-bottom: 0.01em solid #dadada;}';
html+='#'+boxid+'>dl>ol>*{margin: 0 0.05em;flex-grow:1;display:flex;justify-content: center;align-items: center;}';
html+='#'+boxid+'>dl>ol>li{height: 0.4em;cursor:pointer;background:#fff;border:0.01em solid #CFCFCF;border-radius:3px;transition:background .3s;}';
html+='#'+boxid+'>dl>ol>li.checked{color:#fff;background:#00B7EE;border-color:transparent;}';
html+='#'+boxid+'>dl>dd{position:relative;width: 100%;padding: 0.05em;padding-top: 0.05em;overflow: auto;flex: 1 1;}';
html+='#'+boxid+'>dl ul{border:3px dashed #E6E6E6;overflow: auto;width: 100%;height: 100%;display: flex;flex-wrap: wrap;align-content: flex-start;}';
html+='#'+boxid+'>dl ul::-webkit-scrollbar {display: none;}';
html+='#'+boxid+' *[dir]{width: 100%;height: 0.28em;display: flex;align-items: center;padding-left: 0.16em;background: url('+__DIR__+'/image/dir.png) 0.03em 0.05em no-repeat;background-size: auto 0.18em;cursor: pointer;}';
html+='#'+boxid+' *[dir]:first-child{height: 0.2em;padding: 0;background: none;}';
html+='#'+boxid+' *[dir]:nth-child(even){background-color: #fafafa;}';
html+='#'+boxid+' *[file]{width: 1.2em;height: 1.2em;position: relative;margin: 0.01em;border: 0.01em solid #ccc;overflow: hidden;display: flex;justify-content: center;align-items: center;}';
html+='#'+boxid+' *[file] img{width: 1.2em;height: 1.2em;object-fit: cover;}';
html+='#'+boxid+' *[file] b{position: absolute;z-index: 2;right: 0;top: 0;height: 100%;width: 100%;background: rgba(0,0,0,.7);transition: width .3s;}';
html+='#'+boxid+' *[file]>i{width: 0.25em;height: 0.25em;position: absolute;top: 0.05em;right: 0.05em;border-radius: 50%;border: 0.02em solid #fff; color: #fff;background: rgba(0,0,0,.3);font-style: normal;display: flex;justify-content: center;align-items: center;cursor: pointer;}';
html+='#'+boxid+' *[file]>i>span{display: none;font-size: 0.16em;}';
html+='#'+boxid+' *[file].checked>i{border: none;background: #00B7EE;}';
html+='#'+boxid+' *[file].checked>i>span{display: block;}';
html+='</style>';
html+='<dl><input id="'+boxid+'-file" multiple="multiple" type="file" style="display: none;">';
html+=' <ol>';
html+=' <li tab="0" class="checked"><span>'+STR['upload']+'</span></li>';
html+=' <li tab="1"><span>'+STR['online']+'</span></li>';
html+=' <p style="width: 0.5em;"></p>';
html+=' <li><span>'+STR['cancel']+'</span></li>';
html+=' <li class="checked"><span>'+STR['ok']+'(<font>0</font>)</span></li>';
html+=' </ol>';
html+=' <dd style="display: block;">';
html+=' <ul><label file for="'+boxid+'-file"><img src="'+__DIR__+'/image/add.png" title="'+STR['select']+'" /></label></ul>';
html+=' </dd>';
html+=' <dd style="display: none;">';
html+=' <ul><p style="width: 100%;"></p></ul>';
html+=' </dd>';
html+='</dl>';
boxdom.id = boxid;
boxdom.style.display = 'none';
boxdom.innerHTML = html;
$('body').append(boxdom);
$menu = $('#'+boxid+'>dl>ol>li[tab]');
$tabs = $('#'+boxid+'>dl>dd');
$num = $('#'+boxid+' ol font');
$input_file = $('#'+boxid+'-file');
//事件绑定
$menu.on('click',function(){
var $this = $(this);
if($this.hasClass('checked')) return;
$menu.removeClass('checked');
$this.addClass('checked');
var tab = $this.attr('tab');
$tabs.hide().eq($this.attr('tab')).show();
})
$('#'+boxid+'>dl>ol>li').eq(2).on('click',function(){
$(boxdom).hide();
if (setup.cancel && typeof(setup.cancel) === 'string') {
(new Function(setup.cancel)).call(setup.thisArg);
} else if (typeof(setup.cancel) === 'function') {
setup.cancel.call(setup.thisArg);
}
})
$('#'+boxid+'>dl>ol>li').eq(3).on('click',function(){
var result = {},files = [];
$('#'+boxid+' ul>li.checked').each(function(){
result[$(this).attr('index')] = $(this).attr('file_url');
})
for (var i in result) {
files.push(result[i])
}
$(boxdom).hide();
if (setup.ok && typeof(setup.ok) === 'string') {
(new Function('files', setup.ok)).call(setup.thisArg, files);
} else if (typeof(setup.ok) === 'function') {
setup.ok.call(setup.thisArg, files);
}
})
//上传文件
$input_file.on('change',function(){
var fs = this.files;
if ( fs.length > setup.max_file ) return tips('最多上传'+setup.max_file+'个文件');
$('#'+boxid+' ul>li.checked').removeAttr('index').removeClass('checked');
var $upload_btn = $tabs.eq(0).find('ul>label');
$upload_btn.hide();
var num = 0, over_num=0;
$.each(this.files, function(f) {
var thisNum = ++num;
var op = {
url: '',
type: file_type(f.name),
checked: true,
index: thisNum,
marsk: true
}
if(!op.type) $.each(mime_map, function(v,k){
if(f.type == v) {
op.type = k;
return false;
}
})
if(is_img(op.type)) op.url = window.URL.createObjectURL(f);
$upload_btn.before( file_html(op) );
var $li = $tabs.eq(0).find('ul>li[index="'+thisNum+'"]');
upload(f, 0);
function oncomplete(){
if(num <= ++over_num) {
$input_file.val('');
$upload_btn.show();
}
}
function onerror(){
$li.remove();
oncomplete();
}
function upload(file, start){
var len = setup.max_size;// 单次上传最多size,超过的会执行断点续传
var over = false;
if(file.size - start < len){
len = file.size - start;
over = true;
}
if(len <= 0) return $li.remove();
var fd = new FormData();
var f = (start==0&&over) ? file : new File([file.slice(start, start + len)], file.name, {type: file.type});
fd.append('file', f);
fd.append('filesize', file.size);
ajax({
url:setup.upload_url,
data: fd,
success: function(res){
if(!over){
var w = (1 - (start+len)/file.size)*100 + '%';
$li.find('b').css('width',w);
return upload(file, start+len);
}
$li.attr('title', res.data).attr('file_url', res.data).find('b').css('width','100%').hide(200);
if(is_img(op.type)) $li.find('img').attr('src', img_src(res.data));
oncomplete();
},
progress: function(pro){
var percent = pro.loaded/pro.total;
var w = (1 - start/file.size - (len/file.size)*percent)*100 + '%';
$li.find('b').css('width',w);
},
error: function(res){
tips(res.message);
onerror();
}
})
}
});
$num.text(num);
})
$tabs.eq(1).find('ul').on('scroll',function(){
get_manage.loop();
})
//全局功能函数
window[boxid+'_imger'] = function(_this){
$(_this).parent().append('<p style="color: #fff;position: absolute;left: 0.13em;top: 0.17em;width: 0.47em;height: 0.2em;display: flex;justify-content: center;align-items: center;"><span>'+_this.getAttribute('type')+'</span></p>');
_this.src = __DIR__+'/image/type/__root.png';
}
window[boxid+'_preview'] = function(_this){
window.open(_this.parentNode.getAttribute('file_url'),'_blank');
}
window[boxid+'_select'] = function(_this){
var $file_li = $(_this.parentNode);
var $checked = $('#'+boxid+' ul>li.checked');
if ($file_li.hasClass('checked')) {
var cache_i,this_i = $file_li.attr('index');
$checked.each(function(){
cache_i = $(this).attr('index');
if(cache_i > this_i){
$(this).attr('index', (cache_i-1)).find('i>span').text(cache_i-1);
}
})
$file_li.removeClass('checked').removeAttr('index').find('i>span').text('');
$num.text($checked.length-1);
} else{
if ($checked.length >= setup.max_file) return tips('最多选择'+setup.max_file+'个文件');
$file_li.addClass('checked').attr('index', $checked.length+1).find('i>span').text($checked.length+1);
$num.text($checked.length+1);
}
}
window[boxid+'_dir'] = function(_this){
var dir_name = $(_this).attr('dir_name');
if (dir_name=='../' && dir_stack.length>1) {
dir_stack.pop();
} else{
dir_stack.push(dir_name);
}
get_manage(dir_stack[dir_stack.length-1]);
}
}
function file(config){
if(!boxdom) init();
rem = $.rem.get();
boxdom.style.fontSize = rem+'px';
//初始化管理器
$menu.removeClass('checked').hide();
$tabs.hide();
$num.text(0);
$input_file.removeAttr('accept');
dir_stack=[''];
//配置上传设置
setup = $.merge({accept: '', max_file: 1, max_size: 10*1024*1024}, config);
if(setup.upload_url) {
$menu.eq(0).show().addClass('checked');
$tabs.eq(0).show();
if(setup.filelist_url) $menu.eq(1).show();
}else if(setup.filelist_url){
$menu.eq(1).show().addClass('checked');
$tabs.eq(1).show();
}else{
throw new Error(STR['no_url']);
}
if (setup.accept) {
var accept=[];
setup.accept.split(',').forEach(function(row){
if (row in mime_map) accept.push(mime_map[row]);
})
$input_file.attr('accept',accept.join(','));
}
setup.name = setup.name || 'file';
$tabs.eq(0).find('ul li').remove();
$tabs.eq(0).find('ul>label').show();
get_manage();
$(boxdom).show();
}
module.exports = file;
})(require('s94-web'));