landers.upload
Version:
landers.upload
873 lines (756 loc) • 26.8 kB
JavaScript
/**
* class Landers.upload
* @param {[type]} $container [description]
* @param {[type]} $input [description]
* @param {[type]} key [description]
* @param {[type]} opts [description]
* @return {[type]} [description]
*/
Landers.upload = function($container, $input, key, opts){
opts = opts || {};
this.key = key;
this.container = $('<ul class="landers-upload"></ul>').appendTo($container);
this.input = $input;
this.apiUrl = opts.apiUrl || '/upload';
this.scope = opts.scope;
this.opts = {};
this.enable = opts.enable === false ? false : true;
this.$tip = opts.$tip;
this.amount = opts.amount || 0;
this.debug = opts.debug || false;
var me = this;
this.instanceOptions= {
key: key,
apiUrl: this.apiUrl,
size: opts.size ? opts.size : {width: 150, height: 120},
debug: this.debug,
attrClass: opts.attrClass,
onUploade: function(){
var data = me.getValue();
opts.onUploade && opts.onUploade();
opts.onChange && opts.onChange(data);
},
onRemove: function(){
var data = me.getValue();
opts.onRemove && opts.onRemove();
opts.onChange && opts.onChange(data);
},
onChange: function(){
var data = me.getValue();
opts.onChange && opts.onChange(data);
}
};
this.init();
};
/**
* 与服务端通信
* @param {[type]} act [description]
* @param {[type]} params [description]
* @return {[type]} [description]
*/
Landers.upload.prototype.server = function(act, params){
var me = this;
params = $.extend(params || {}, {
act: act,
key: me.key
});
return $.ajax({
url: me.apiUrl,
data: params,
dataType: 'json',
type: 'GET',
success: function(rspn, textStatus, xhr){
},
error: function(xhr, textStatus, errorThrown){
alert(xhr.responseJSON.message);
}
});
};
/**
* 格式化单项数据结构
* @return {[type]} [description]
*/
Landers.upload.prototype.formatItemData = function( dat ){
dat = dat || '';
if (typeof dat === 'string') {
dat = $.trim(dat);
return {
original: dat,
small: dat,
mini: dat
};
} else {
dat.small = dat.small || dat.original;
dat.mini = dat.mini || dat.original;
return dat;
}
}
/**
* 取得输入数据
* @return {[type]} [description]
*/
Landers.upload.prototype.getInput = function(){
var me = this;
var value = $.trim(me.input.val()) || '';
if ( value ) {
try {
value = $.parseJSON(value);
if ( !$.isArray(value)) {
value = [value];
}
} catch (e) {
value = value.split(',');
}
} else {
value = [];
}
var data = value.map(function(item){
return me.formatItemData(item);
});
// 同步一下
me.setInput( data );
return data;
};
/**
* 将数据回存到input上
* @param {[type]} data [description]
*/
Landers.upload.prototype.setInput = function( data ){
var me = this;
if (data) {
data = JSON.stringify(data);
} else {
data = '';
}
me.input.val( data);
};
/**
* 将数据回存到input上
* @param {[type]} data [description]
*/
Landers.upload.prototype.getValue = function(){
var me = this;
var data = [], $containers = me.instanceContainers();
$containers.each(function(i, item){
var $item = $(item);
var instance = $item.data('instance');
if ( instance.data && instance.data.original ) {
data.push( instance.data );
}
});
if (me.maxAmount() <= 1) {
data = data[0];
}
return data;
}
/**
* 新增实例
* @param {[type]} dat [description]
*/
Landers.upload.prototype.addIntance = function(data){
var me = this;
var instance = new Landers.upload.instance(data, me.instanceOptions);
var instance_contaner = instance.container.eq(0);
instance_contaner.data('instance', instance);
me.container.append( instance_contaner );
};
/**
* 显示界面
* @return {[type]} [description]
*/
Landers.upload.prototype.show = function(){
var me = this.clear();
var data = me.getInput();
var count = Math.max(data.length, me.maxAmount());
for (var i=0; i<=count-1; i++) {
var dat = data[i] || me.formatItemData();
me.addIntance(dat);
}
};
/**
* 初始化
* @return {[type]} [description]
*/
Landers.upload.prototype.init = function(){
var me = this;
me.server('options')
.success(function(rspn){
me.instanceOptions.isAllowRemote = rspn.data.is_allow_remote;
me.instanceOptions.isAllowDelete = rspn.data.is_allow_delete;
me.instanceOptions.csrfToken = rspn.data.csrfToken;
me.instanceOptions.maxAmount = rspn.data.max_amount;
setTimeout(function(){
me.show();
}, 200);
});
};
/**
* 最多实例数量
* @return {[type]} [description]
*/
Landers.upload.prototype.maxAmount = function(){
var me = this;
return me.amount || parseInt(me.instanceOptions.maxAmount) || 1;
};
/**
* 取得所有实例的contaner
* @return {[type]} [description]
*/
Landers.upload.prototype.instanceContainers = function(){
var me = this;
return me.container.children();
};
/**
* 清空所有
* @return {[type]} [description]
*/
Landers.upload.prototype.clear = function(){
var me = this;
me.instanceContainers().remove();
return me;
};
/**
* 清空所有值
* @return {[type]} [description]
*/
Landers.upload.prototype.clearValue = function(){
var me = this;
me.instanceContainers().each(function(i, item){
var $item = $(item);
var instance = $item.data('instance');
if (instance) instance.data = {};
});
me.setInput('');
return me;
};
/**
* class Landers.upload.instance
* @param {[type]} data [description]
* @param {[type]} opts [description]
* @return {[type]} [description]
*/
Landers.upload.instance = function(data, opts){
// 初始化数据
this.data = data;
// 初始化属性
this.key = opts.key;
this.isAllowRemote = opts.isAllowRemote || false;
this.isAllowDelete = opts.isAllowDelete || false;
this.isAllowCutImage = opts.isAllowCutImage || false;
this.size = opts.size;
this.debug = opts.debug;
this.enable = opts.enable !== false;
this.isDirect = opts.isDirect !== false;
this.apiUrl = opts.apiUrl;
this.isRemainOriginalName = opts.isRemainOriginalName;
this.onUploade = opts.onUploade;
this.onChange = opts.onChange;
this.onRemove = opts.onRemove;
this.fileType = null;
this.uploading = false;
this.csrfToken = opts.csrfToken;
this.attrClass = opts.attrClass;
// 初始界面和事件
this.container = $(this.buildHtml('normal'));
this.preview = this.container.find('.upload-preview');
this.initData()
.initContainer()
.initHoverEvent()
.initButtonEvent()
.show()
.setButtonVisiableOrHidden();
};
/**
* 初始化方法集
* @type {Object}
*/
Landers.upload.instance.prototype = {
_getExtensionName: function(path){
var me = this;
var file_info = Landers.path.parse(path);
if (file_info) {
if ( file_info.extname ) {
return file_info.extname.toLowerCase();
} else if (file_info.query) {
for (var k in file_info.query) {
var ext_name = file_info.query[k];
if (me.isImageType(ext_name)) {
return ext_name;
}
}
}
}
return '';
},
initContainer: function(){
var me = this;
// 初始化containerl界面
me.container.css(me.size);
if ( me.attrClass ) me.container.addClass(me.attrClass);
me.preview.css({
width: me.size.width - 4,
height: me.size.height - 4,
});
// 触发mouseout 事件
setTimeout(function(){
me.container.trigger('mouseout');
}, 1500);
me.container.find('[data-toggle="tooltip"]').tooltip();
return me;
},
initData: function(){
var me = this;
me.data = me.data || {};
me.data.original = me.data.original || '';
me.data.small = me.data.small || '';
me.data.mini = me.data.mini || '';
me.fileType = me._getExtensionName(me.data.original);
return me;
},
/**
* 初始化hover事件
* @param {[type]} $instance [description]
* @return {[type]} [description]
*/
initHoverEvent: function($instance){
var me = this;
me.container.hover(
function(){
if ( me.uploading ) return;
var $btns = $(this).find('.buttons');
$btns.stop().animate({bottom: '0px'} , 300);
},
function(){
var $btns = $(this).find('.buttons');
$btns.stop().animate({'bottom':'-' + $btns.height() + 'px'}, 300);
}
);
return me;
},
setButtonVisiableOrHidden: function(){
var me = this;
//隐藏第1个实例的左移按钮
setTimeout(function(){
// 向前、向后移 按钮
var $siblings = me.container.siblings().add(me.container);
$siblings.find('.btn-move-prev, .btn-move-next').parent().show();
$first = $siblings.filter(':first');
$last = $siblings.filter(':last');
$first.find('.btn-move-prev').parent().hide();
$last.find('.btn-move-next').parent().hide();
// 删除按钮
me.container.find('.btn-remove').parent().ifShow( me.data && me.data.original );
// 图像工具
me.container.find('.btn-image-tools').parent().ifShow( me.isImageType() );
// 下载链接
me.container.find('.btn-download-file').parent().ifShow( me.data && me.data.original, function( bool ){
$(this).children('a').attr({'href': me.data.original, 'target': '_blank'});
});
}, 50)
return me;
},
/**
* 初始化按钮事件
* @param {[type]} $instance [description]
* @return {[type]} [description]
*/
initButtonEvent: function(){
var me = this;
me.container.find('input[name=file]').change(function(){
var value = $(this).val();
if ( value ) {
me.fileType = me._getExtensionName(value);
me.uploadLocal( $(this) );
}
});
me.container.find('.btn-remove').click(function(){
if ( me.isAllowDelete ) {
if ( !confirm('确定要删除吗?') ) return;
me.remove($(this));
me.container.showTopResponse('success', '文件已删除', 1000);
} else {
if ( !confirm('确定要移除吗?') ) return;
me.remove($(this));
me.container.showTopResponse('success', '文件已移除', 1000);
}
});
me.container.find('.btn-upload-remote').click(function(){
me.uploadRemote($(this));
});
me.container.find('.btn-move-prev').click(function(){
var $container = $(this).closest('.upload-item');
var $prev = $container.prev();
if (!$prev.length) return;
$prev.before($container);
me.setButtonVisiableOrHidden();
me.onChange && me.onChange();
});
me.container.find('.btn-move-next').click(function(){
var $container = $(this).closest('.upload-item');
var $next = $container.next();
if (!$next.length) return;
$next.after($container);
me.setButtonVisiableOrHidden();
me.onChange && me.onChange();
});
return me;
}
};
/**
* 生成HTML
* @param {[type]} key [description]
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.buildHtml = function(key){
var me = this, str = '';
switch(key) {
case 'dialog_upload_remote':
str += '<div class="zoc p5 pb0">';
str += ' <span class="fl">粘贴URL到以下文本框内</span>';
if ( me.isAllowRemote )
str += ' <label class="fr"><input type="checkbox" id="is_allow_getremote" checked/>抓取到服务器</label>';
str += '</div>';
str += '<div class="tc ph5"><input type="text" id="remoteurl" class="text noime" style="width:98%; padding:3px;"></div>';
break;
case 'dialog_cut_image':
str += '<form>';
str += '<table width="100%" height="100%">';
str += '<tr><td class="wrap-jcrop">';
str += ' <img src="{url}" onload="Landers.image.auto(this, true, 800, 600, true)" style="margin:0 auto;"/>';
str += '</td></tr>';
str += '</table>';
str += '<input name="x" type="hidden"/>';
str += '<input name="y" type="hidden"/>';
str += '<input name="w" type="hidden"/>';
str += '<input name="h" type="hidden"/>';
str += '<input name="img_w" type="hidden"/>';
str += '<input name="img_h" type="hidden"/>';
str += '<input name="url" type="hidden"/>';
str += '</form>';
break;
case 'file':
str = '<input name="file" type="file" ContentEditable="false">';
break;
case 'normal':
str += '<li class="upload-item">';
str += '<div class="upload-preview">';
str += '<div class="preview-flash"></div>';
str += '<img src="" class="preview-image" onload="Landers.image.auto(this, true, ' + (me.size.width - 4) + ', ' + (me.size.height - 4) + ', true)"/>';
str += '<div class="preview-file-type"><div></div></div>';
str += '</div>';
if ( me.enable ) {
str += '<div class="buttons"><table border="0" width="100%" height="100%"><tr>';
str += '<td style="display:none"><a class="button btn-move-prev" href="javascript:;" data-toggle="tooltip" data-placement="top" title="向前移">';
str += ' <i class="glyphicon glyphicon-chevron-left"></i>';
str += '</a></td>';
str += '<td><a class="button btn-upload-local" href="javascript:;" data-toggle="tooltip" data-placement="top" title="上传或重传">';
str += '<i class="glyphicon glyphicon-open"></i>';
str += me.buildHtml('file');
str += '</a></td>';
str += '<td style="display:none"><a class="button btn-download-file" href="#" data-toggle="tooltip" data-placement="top" title="下载文件">';
str += '<i class="glyphicon glyphicon-save"></i>';
str += '</a></td>';
if ( me.isAllowRemote ){
str += '<td><a class="button btn-upload-remote" href="javascript:;" data-toggle="tooltip" data-placement="top" title="引用外部资源">';
str += '<input type="hidden" name="url"/>';
str += '<i class="glyphicon glyphicon-link"></i>';
str += '</a></td>';
}
if ( me.isAllowDelete ) {
str += ' <td style="display:none"><a class="button btn-remove" href="javascript:;" data-toggle="tooltip" data-placement="top" title="移除文件">';
str += '<i class="glyphicon glyphicon-trash"></i>';
str += ' </a></td>';
}
// str += ' <td class="image-tools-buttons">';
// str += ' <a class="button btn-image-tools" href="javascript:;" data-toggle="tooltip" data-placement="top" title="图像工具">';
// str += '<i class="glyphicon glyphicon-picture"></i>';
// str += ' </a>';
// str += ' <ul class="vlist">';
// str += ' <li><a class="button btn-cut-image" href="javascript:;" title="裁剪"><i class="glyphicon glyphicon-wrench"></i></a></li>';
// str += ' <li><a class="button btn-rotate-0" href="javascript:;" title="旋转到0°"> 0° </a></li>';
// str += ' <li><a class="button btn-rotate-90" href="javascript:;" title="旋转到90°"> 90° </a></li>';
// str += ' <li><a class="button btn-rotate-180" href="javascript:;" title="旋转到180°"> 180° </a></li>';
// str += ' <li><a class="button btn-rotate-270" href="javascript:;" title="旋转到270°"> 270° </a></li>';
// str += ' </ul>';
// str += ' </td>';
str += '<td style="display:none"><a class="button btn-move-next" href="javascript:;" data-toggle="tooltip" data-placement="top" title="向后移">';
str += ' <i class="glyphicon glyphicon-chevron-right"></i>';
str += '</a></td>';
str += '</tr></table></div>';
}
str += '</li>';
};
return str;
};
/**
* 是否是图像类型
* @param {[type]} type [description]
* @return {Boolean} [description]
*/
Landers.upload.instance.prototype.isImageType = function(type){
var me = this;
type = type || me.fileType;
return $.inArray(type, [
'jpg', 'jpeg', 'gif', 'png', 'bmp', 'ico'
]) >= 0;
};
Landers.upload.instance.prototype.getAbsoluteUrl = function(url){
return url;
};
/**
* 显示界面
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.show = function(){
var me = this;
//对于显示来说,优先级为:small > mini > original (originall图片体积偏大)
var url = me.getAbsoluteUrl( me.data.small || me.data.mini || me.data.original );
if ( !url ) return me;
var url_info = Landers.url.parse(url);
var ext_name = url_info.extname || '未知类型';
ext_name = ext_name.toLowerCase();
if ( me.isImageType(ext_name) ) {
me.previewImage(url);
} else {
switch( ext_name ){
case 'swf':; case 'flv' :
me.previewFlash( url );
break;
case 'mp3':
me.previewAudio(url);
break;
case 'mp4':
me.previewVideo(url);
break;
default:
me.previewFileType( ext_name );
break;
}
}
return me;
};
Landers.upload.instance.prototype.clearPreview = function(){
var me = this;
me.preview.children().hide();
}
/**
* 预览Flash
* @param {[type]} url [description]
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.previewFlash = function(url){
var me = this;
me.clearPreview();
var $preview = me.preview.find('.preview-flash').show();
// Landers.loader.jsm('landers.flash', function(){
// Landers.flash.show($preview, url, me.size.width, me.size.height);
// });
};
/**
* 预览图像
* @param {[type]} url [description]
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.previewImage = function(url){
var me = this;
me.clearPreview();
var $preview = me.preview.find('.preview-image').show();
$preview.attr('src', url);
if ( !url ) $preview.hide();
};
/**
* 预览文件类型
* @param {[type]} url [description]
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.previewFileType = function( type ){
var me = this;
me.clearPreview();
var $preview = me.preview.find('.preview-file-type').show();
$preview.children().attr('class', '').addClass('file-type-' + type)
};
/**
* 预览音频
* @param {[type]} url [description]
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.previewAudio = function(text){
var me = this;
me.clearPreview();
var $preview = me.preview.find('.preview-audio').show();
};
/**
* 预览视频
* @param {[type]} url [description]
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.previewVideo = function(text){
var me = this;
me.clearPreview();
var $preview = me.preview.find('.preview-video').show();
};
/**
* 生成IFrameID
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.generateUploadIframeID = function(){
var me = this;
var date = new Date(),
uniqid = [
date.getYear(),
date.getMonth() + 1,
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds()
].join('');
return 'UploadResult' + '_' + me.key + '_' + me.container.index() + '_' + uniqid;
};
/**
* 上传本地文件
* @param {[type]} $input [description]
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.uploadLocal = function($input){
var me = this;
if (!me.enable || !me.isDirect) return;
// 记录input 原 parent
var $button = $input.parent();
me.container.showTopResponse('loading', '上传中...', 500, function(){
me.uploading = true;
//创建IFRAME
var iframe_name = me.generateUploadIframeID();
$iframe = $('<iframe name="' + iframe_name + '" src="about:blank" class="upload-iframe"></iframe>');
me.container.append( $iframe );
//创建上传表单
$input.wrap('<form encType="multipart/form-data" class="upload-form"></form>');
if ( me.debug) iframe_name = '_blank';
var $form = $input.parent().attr({
target: iframe_name,
method: 'post',
action: Landers.url.qs.set( me.apiUrl, {act: 'upload'})
});
$form.append( $('<input name="key" type="hidden"/>').val(me.key) );
$form.append( $('<input name="_token" type="hidden"/>').val(me.csrfToken) );
// 是否使用原来的文件名
if (me.data && me.data.val && me.isRemainOriginalName){
$form.append( $('<input name="filename" type="hidden"/>').val(me.data.val) );
}
function strip_html(str) {
var reTag = /<(?:.|\s)*?>/g;
return str.replace(reTag,"");
}
function get_upload_result(){
var ret = Landers.iframe.html($iframe);
if ( !ret ) return;
var content = strip_html(ret);
try {
return $.parseJSON(content);
} catch(e) {
if (content.indexOf('413 Request Entity Too Large')) {
return {
success: false,
message: '上传文件过大'
};
}
if (content.indexOf('404 Http Not Found')) {
return {
success: false,
message: '404 Http Not Found'
};
}
return {
success: false,
message: content
};
}
}
function wait_for_upload(callback){
var rspn = get_upload_result();
var self = arguments.callee;
if ( rspn ){
// 处理成功与否
if ( !rspn.success ) {
me.container.showTopResponse('error', rspn.message, 3000);
} else {
me.container.showTopResponse('success', '上传成功', 3000);
me.data = {
original: rspn.data.url,
small: rspn.data.url_small,
mini: rspn.data.url_mini
};
};
me.uploading = false;
me.show();
// 上传结束后的回调
callback && callback();
} else {
setTimeout(function(){
self( callback );
}, 200);
}
}
var handle_after_upload = function(){
// 上传结束后将 $input清空并移回原处
$button.append( $input.val('') );
// 销毁 form
$form.remove();
// 销毁 iframe
$iframe.remove();
// 设置按钮
me.setButtonVisiableOrHidden();
// 回调
me.onUploade && me.onUploade.call(me);
};
// 提交表单,触发上传
$('body').append($form);
$form.trigger('submit');
// 监听 iframe 内容
Landers.iframe.ready( $iframe, function(){
wait_for_upload( handle_after_upload );
});
});
};
/**
* 移除
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.remove = function(){
var me = this;
me.data = {};
me.previewImage();
me.onRemove && me.onRemove();
me.setButtonVisiableOrHidden();
};
/**
* 销毁实例
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.destroy = function(){
me.container.unbind('hover')
me.container.find('*').unbind('click').unbind('change');
me.container.remove();
};
/**
* 上传远程文件
* @return {[type]} [description]
*/
Landers.upload.instance.prototype.uploadRemote = function($event){
var me = this;
var remote_url = prompt('输入引用的资源 URI:');
if ( remote_url ) {
me.container.showTopResponse('success', '引用成功', 3000);
me.data = {
original: remote_url,
small: remote_url,
mini: remote_url
};
} else {
me.container.showTopResponse('warning', '取消引用', 3000);
}
$event.trigger('blur');
me.show();
// 回调
me.onUploade && me.onUploade.call(me);
};
Landers.upload.instance.plugins = {};