@tower1229/flow-ui
Version:
Highly customizable UI framework based Seajs/jQuery
437 lines (404 loc) • 12.3 kB
JavaScript
/*
* name: upload
* version: 1.2.0
* update: 新增headers设置
* date: 2017-12-12
* base: https://github.com/aralejs/upload
*/
define('upload', function(require, exports, module) {
'use strict';
var $ = window.$ || require('jquery'),
iframeCount = 0,
DEFAULT = {
trigger: null,
name: null,
action: null,
headers: {},
data: null,
accept: null,
change: null,
error: null,
multiple: true,
compress: false,
compressOption: {},
success: null
};
function Uploader(options) {
if (!(this instanceof Uploader)) {
return new Uploader(options);
}
if (isString(options)) {
options = {
trigger: options
};
}
var settings = $.extend({}, DEFAULT, options || {});
var $trigger = $(settings.trigger);
settings.action = settings.action || $trigger.data('action') || '/upload';
settings.name = settings.name || $trigger.attr('name') || $trigger.data('name') || 'file';
settings.data = settings.data || parse($trigger.data('data'));
settings.accept = settings.accept || $trigger.data('accept');
settings.success = settings.success || $trigger.data('success');
this.settings = settings;
this.setup();
this.bind();
}
// initialize
// create input, form, iframe
Uploader.prototype.setup = function() {
this.form = $(
'<form method="post" enctype="multipart/form-data"' + 'target="" action="' + this.settings.action + '" />'
);
this.iframe = newIframe();
this.form.attr('target', this.iframe.attr('name'));
var data = this.settings.data;
if($.isPlainObject(data)){
this.form.append(createInputs(data));
}
if (window.FormData) {
this.form.append(createInputs({
'_uploader_': 'formdata'
}));
} else {
this.form.append(createInputs({
'_uploader_': 'iframe'
}));
}
var input = document.createElement('input');
input.type = 'file';
input.name = this.settings.name;
if (this.settings.accept) {
input.accept = this.settings.accept;
}
if (this.settings.multiple) {
input.multiple = true;
input.setAttribute('multiple', 'multiple');
}
this.input = $(input);
var $trigger = $(this.settings.trigger);
this.input.attr('hidefocus', true).css({
position: 'absolute',
top: 0,
right: 0,
opacity: 0,
outline: 0,
cursor: 'pointer',
height: $trigger.outerHeight(),
fontSize: Math.max(64, $trigger.outerHeight() * 5)
});
this.form.append(this.input);
this.form.css({
position: 'absolute',
top: $trigger.offset().top,
left: $trigger.offset().left,
overflow: 'hidden',
width: $trigger.outerWidth(),
height: $trigger.outerHeight(),
zIndex: findzIndex($trigger) + 10
}).appendTo('body');
return this;
};
// bind events
Uploader.prototype.bind = function() {
var self = this;
var $trigger = $(self.settings.trigger);
$trigger.mouseenter(function() {
self.form.css({
top: $trigger.offset().top,
left: $trigger.offset().left,
width: $trigger.outerWidth(),
height: $trigger.outerHeight()
});
});
self.bindInput();
};
Uploader.prototype.compressList = [];
Uploader.prototype.bindInput = function() {
var self = this;
//缩略图
if ($.isFunction(self.settings.thumb)) {
require.async('makethumb', function() {
$(self.input).makeThumb($.extend({
done: function(dataURL, file) {
self.settings.thumb(dataURL, file);
}
}, self.settings.thumbOption));
});
}
self.input.change(function(e) {
// ie9 don't support FileList Object
// http://stackoverflow.com/questions/12830058/ie8-input-type-file-get-files
self._files = this.files || [{
name: e.target.value
}];
var file = self.input.val();
if (self.settings.compress) {
require.async('localResizeIMG', function(lrz) {
$.each(self._files, function(i, file) {
lrz(file, $.extend(self.settings.compressOption, {
fieldName: self.settings.name
})).then(function(rst) {
self.compressList.push(rst.formData);
if ($.isFunction(self.settings.change)) {
self.settings.change.call(self, self._files);
} else if (file) {
return self.submit();
}
});
});
});
} else {
if ($.isFunction(self.settings.change)) {
self.settings.change.call(self, self._files);
} else if (file) {
return self.submit();
}
}
});
};
// handle submit event
// prepare for submiting form
Uploader.prototype.submit = function() {
var self = this;
if (window.FormData) {
var form;
var ajaxUpload = function(form) {
var optionXhr;
if (self.settings.progress) {
optionXhr = function() {
var xhr = $.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position; /*event.position is deprecated*/
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
self.settings.progress(event, position, total, percent);
}, false);
}
return xhr;
};
}
$.ajax({
url: self.settings.action,
type: 'post',
headers: self.settings.headers,
processData: false,
contentType: false,
data: form,
xhr: optionXhr,
context: this,
success: self.settings.success,
error: self.settings.error
});
};
if (self.compressList.length) {
$.each(self.compressList, function(i, form) {
ajaxUpload(form);
});
self.compressList.length = 0;
self._files = null;
} else {
// build a FormData
if(typeof self.settings.data === 'function'){
self.form.append(createInputs(self.settings.data()));
}
// use FormData to upload
form = new FormData(self.form.get(0));
if(self._files){
form.append(self.settings.name, self._files);
}
ajaxUpload(form);
}
return this;
} else if (self._files) {
// iframe upload
self.iframe = newIframe();
self.form.attr('target', self.iframe.attr('name'));
$('body').append(self.iframe);
self.iframe.one('load', function() {
// https://github.com/blueimp/jQuery-File-Upload/blob/9.5.6/js/jquery.iframe-transport.js#L102
// Fix for IE endless progress bar activity bug
// (happens on form submits to iframe targets):
$('<iframe src="javascript:false;"></iframe>')
.appendTo(self.form)
.remove();
var response;
try {
response = $(this).contents().find("body").html();
} catch (e) {
response = "cross-domain";
}
$(this).remove();
if (!response) {
if (self.settings.error) {
self.settings.error(self.input.val());
}
} else {
if (self.settings.success) {
self.settings.success(response);
}
}
});
self.form.submit();
}
return this;
};
Uploader.prototype.refreshInput = function() {
//replace the input element, or the same file can not to be uploaded
var newInput = this.input.clone();
this.input.before(newInput);
this.input.off('change');
this.input.remove();
this.input = newInput;
this.bindInput();
};
// handle change event
// when value in file input changed
Uploader.prototype.change = function(callback) {
if (!callback) {
return this;
}
this.settings.change = callback;
return this;
};
// handle when upload success
Uploader.prototype.success = function(callback) {
var me = this;
this.settings.success = function(response) {
me.refreshInput();
if (callback) {
callback(response);
}
};
return this;
};
// handle when upload success
Uploader.prototype.error = function(callback) {
var me = this;
this.settings.error = function(response) {
if (callback) {
me.refreshInput();
callback(response);
}
};
return this;
};
// enable
Uploader.prototype.enable = function() {
this.input.prop('disabled', false);
this.input.css('cursor', 'pointer');
};
// disable
Uploader.prototype.disable = function() {
this.input.prop('disabled', true);
this.input.css('cursor', 'not-allowed');
};
// Helpers
// -------------
function isString(val) {
return Object.prototype.toString.call(val) === '[object String]';
}
function createInputs(data) {
if (!data) return [];
var inputs = [],
i;
for (var name in data) {
i = document.createElement('input');
i.type = 'hidden';
i.name = name;
i.value = data[name];
inputs.push(i);
}
return inputs;
}
function parse(str) {
if (!str) return {};
var ret = {};
var pairs = str.split('&');
var unescape = function(s) {
return decodeURIComponent(s.replace(/\+/g, ' '));
};
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
var key = unescape(pair[0]);
var val = unescape(pair[1]);
ret[key] = val;
}
return ret;
}
function findzIndex($node) {
var parents = $node.parentsUntil('body');
var zIndex = 0;
for (var i = 0; i < parents.length; i++) {
var item = parents.eq(i);
if (item.css('position') !== 'static') {
zIndex = parseInt(item.css('zIndex'), 10) || zIndex;
}
}
return zIndex;
}
function newIframe() {
var iframeName = 'iframe-uploader-' + iframeCount;
var iframe = $('<iframe name="' + iframeName + '" />').hide();
iframeCount += 1;
return iframe;
}
function MultipleUploader(options) {
if (!(this instanceof MultipleUploader)) {
return new MultipleUploader(options);
}
if (isString(options)) {
options = {
trigger: options
};
}
var $trigger = $(options.trigger);
var uploaders = [];
$trigger.each(function(i, item) {
options.trigger = item;
uploaders.push(new Uploader(options));
});
this._uploaders = uploaders;
}
MultipleUploader.prototype.submit = function() {
$.each(this._uploaders, function(i, item) {
item.submit();
});
return this;
};
MultipleUploader.prototype.change = function(callback) {
$.each(this._uploaders, function(i, item) {
item.change(callback);
});
return this;
};
MultipleUploader.prototype.success = function(callback) {
$.each(this._uploaders, function(i, item) {
item.success(callback);
});
return this;
};
MultipleUploader.prototype.error = function(callback) {
$.each(this._uploaders, function(i, item) {
item.error(callback);
});
return this;
};
MultipleUploader.prototype.enable = function() {
$.each(this._uploaders, function(i, item) {
item.enable();
});
return this;
};
MultipleUploader.prototype.disable = function() {
$.each(this._uploaders, function(i, item) {
item.disable();
});
return this;
};
MultipleUploader.Uploader = Uploader;
module.exports = MultipleUploader;
});