UNPKG

landers.upload

Version:

landers.upload

873 lines (756 loc) 26.8 kB
/** * 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 = {};