记录:关于Drag&Drop Upload
虽然google gears已经停止开发了,但是依旧没有退出浏览器,加上现在的html5 Binary,支持拖拽上传的浏览器其实已经不少了,各大互联网公司也都用在了实际的项目上,光是邮箱就有gmail,qq邮箱,163等一线邮箱产品在现代浏览器上都实现了拖拽上传。
前一阵我看园子里的朋友 jelle 就发了篇拖拽上传的文。我也好奇,拉下来看了看。-- google gears 和 html5 Binary : )
所以就拿他的代码稍微改了改,就当是转载, 原文在http://www.cnblogs.com/idche/archive/2010/11/24/1886482.html
另外也当自己记录吧,稍微封装了一下下,不完善而且还有bug,配置里面没有对上传文件大小和后缀名的限制接口。
唉..先不管了,先放这里,以后要用的时候再改改,添点东西
/*
* drag - drop to upload file
* by hongru.chenhr[at]gmail.com
* at 2011.04.21
*/
(function () {
// private methods
var _ = {
extend: function (target, source, overwrite) {
if (overwrite == undefined) overwrite = true;
for (var p in source) {
if (!(p in target) || overwrite) {
target[p] = source[p]
}
}
return target;
},
log: function (msg, cat) {
!!window.console && console[(cat ? cat : 'debug')](msg);
},
addEvent: function (o, e, f) {
o.addEventListener ? o.addEventListener(e, f, false) : o.attachEvent('on'+e, function () {f.call(o)});
}
}
// main function
var DDUpload = function (config) {
this.setConfig(config);
this.init();
}
_.extend(DDUpload.prototype, {
setConfig: function (config) {
this.config = {
name: 'yourFileName',
action: 'yourAction',
target: window,
onloadstart: function () {},
onprogress: function (e) {},
oncomplete: function (response) {}
}
_.extend(this.config, config || {});
},
init: function () {
var c = this.config, _this = this;
// prevent default of dragenter and dragover
_.addEvent(window, 'dragenter', this.preventDefault);
_.addEvent(window, 'dragover', this.preventDefault);
if (!!window.google && google.gears) {
/* google.gears
* http://code.google.com/intl/zh-CN/apis/gears/api_httprequest.html
*/
this.xhr = google.gears.factory.create('beta.httprequest');
_.addEvent(c.target, 'drop', function (e) {
_this.googleGears(e);
})
} else if (!!XMLHttpRequest && !!new XMLHttpRequest().sendAsBinary) {
// html5 XMLHttpRequest
this.xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
_.addEvent(c.target, 'drop', function (e) {
_this.html5Binary(e);
})
}
},
preventDefault: function (e) {
e = e || window.event;
if (e && e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
if (e && e.preventDefault) e.preventDefault();
else e.returnValue = false;
},
googleGears: function (e) {
this.preventDefault(e);
var _this = this;
try {
var desktop = google.gears.factory.create('beta.desktop'),
data = desktop.getDragData(e, 'application/x-gears-files'),
file = data.files[0];
var d = this.googleBuild(file);
this.xhr.onloadstart = this.config.onloadstart;
this.xhr.upload.onprogress = this.config.onprogress;
this.xhr.onreadystatechange = function () {
if (_this.xhr.readyState === 4) {
_this.config.oncomplete.call(_this, _this.xhr.responseText);
}
}
this.xhr.open("POST", this.config.action);
this.xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + d.boundary);
this.xhr.send(d.builder.getAsBlob());
//this.xhr.onloadstart(file);
} catch(e) {
}
},
googleBuild: function (file) {
var boundary = '--multipartformboundary' + (+new Date),
dashdash = '--',
crlf = '\n';
var builder = google.gears.factory.create('beta.blobbuilder');
builder.append(dashdash);
builder.append(boundary);
builder.append(crlf);
builder.append('Content-Disposition: form-data; name="'+ this.config.name +'"');
if (file.name) {
builder.append('; filename="' + file.name + '"');
}
builder.append(crlf);
builder.append('Content-Type: application/octet-stream');
builder.append(crlf);
builder.append(crlf);
/* Append binary data. */
builder.append(file.blob);
builder.append(crlf);
/* Write boundary. */
builder.append(dashdash);
builder.append(boundary);
builder.append(crlf);
/* Mark end of the request. */
builder.append(dashdash);
builder.append(boundary);
builder.append(dashdash);
builder.append(crlf);
return {
builder: builder,
boundary: boundary
}
},
/* ====== for html5Binary ======= */
html5Binary: function (e) {
var _this = this;
if (e.dataTransfer.files.length == 0) return;
this.preventDefault(e);
var file = e.dataTransfer.files[0];
var b = this.binaryBuild(file.name, file.getAsBinary());
this.xhr.onloadstart = this.config.onloadstart;
this.xhr.onuploadprogress = this.config.onprogress;
this.xhr.onreadystatechange = function () {
if (_this.xhr.readyState === 4) {
_this.config.oncomplete.call(_this, _this.xhr.responseText);
}
}
this.xhr.open('POST', this.config.action, true);
this.xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + b.boundary);
this.xhr.setRequestHeader('Content-Length', file.size);
this.xhr.overrideMimeType('text/plain; charset=x-user-defined-binary'); //read.readAsDataURL(file);
this.xhr.sendAsBinary(b.builder);
},
binaryBuild: function (name, binary) {
var boundary = '--fileupload'+(+new Date),
dashdash = '--',
crlf = '\n';
var builder = '';
builder += dashdash;
builder += boundary;
builder += crlf;
/* httprequest header */
builder += 'Content-Disposition: form-data; name="'+ this.config.name +'"';
if (name) {
builder += '; filename="' + encodeURIComponent(name) + '"';
}
builder += crlf;
builder += 'Content-Type: application/octet-stream';
builder += crlf;
builder += crlf;
/* build Binary data */
builder += binary;
builder += crlf;
/* Write boundary. */
builder += dashdash;
builder += boundary;
builder += crlf;
/* Mark end of the request. */
builder += dashdash;
builder += boundary;
builder += dashdash;
builder += crlf;
return {
builder: builder,
boundary: boundary
}
}
})
this.DDUpload = DDUpload;
})();
* drag - drop to upload file
* by hongru.chenhr[at]gmail.com
* at 2011.04.21
*/
(function () {
// private methods
var _ = {
extend: function (target, source, overwrite) {
if (overwrite == undefined) overwrite = true;
for (var p in source) {
if (!(p in target) || overwrite) {
target[p] = source[p]
}
}
return target;
},
log: function (msg, cat) {
!!window.console && console[(cat ? cat : 'debug')](msg);
},
addEvent: function (o, e, f) {
o.addEventListener ? o.addEventListener(e, f, false) : o.attachEvent('on'+e, function () {f.call(o)});
}
}
// main function
var DDUpload = function (config) {
this.setConfig(config);
this.init();
}
_.extend(DDUpload.prototype, {
setConfig: function (config) {
this.config = {
name: 'yourFileName',
action: 'yourAction',
target: window,
onloadstart: function () {},
onprogress: function (e) {},
oncomplete: function (response) {}
}
_.extend(this.config, config || {});
},
init: function () {
var c = this.config, _this = this;
// prevent default of dragenter and dragover
_.addEvent(window, 'dragenter', this.preventDefault);
_.addEvent(window, 'dragover', this.preventDefault);
if (!!window.google && google.gears) {
/* google.gears
* http://code.google.com/intl/zh-CN/apis/gears/api_httprequest.html
*/
this.xhr = google.gears.factory.create('beta.httprequest');
_.addEvent(c.target, 'drop', function (e) {
_this.googleGears(e);
})
} else if (!!XMLHttpRequest && !!new XMLHttpRequest().sendAsBinary) {
// html5 XMLHttpRequest
this.xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
_.addEvent(c.target, 'drop', function (e) {
_this.html5Binary(e);
})
}
},
preventDefault: function (e) {
e = e || window.event;
if (e && e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
if (e && e.preventDefault) e.preventDefault();
else e.returnValue = false;
},
googleGears: function (e) {
this.preventDefault(e);
var _this = this;
try {
var desktop = google.gears.factory.create('beta.desktop'),
data = desktop.getDragData(e, 'application/x-gears-files'),
file = data.files[0];
var d = this.googleBuild(file);
this.xhr.onloadstart = this.config.onloadstart;
this.xhr.upload.onprogress = this.config.onprogress;
this.xhr.onreadystatechange = function () {
if (_this.xhr.readyState === 4) {
_this.config.oncomplete.call(_this, _this.xhr.responseText);
}
}
this.xhr.open("POST", this.config.action);
this.xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + d.boundary);
this.xhr.send(d.builder.getAsBlob());
//this.xhr.onloadstart(file);
} catch(e) {
}
},
googleBuild: function (file) {
var boundary = '--multipartformboundary' + (+new Date),
dashdash = '--',
crlf = '\n';
var builder = google.gears.factory.create('beta.blobbuilder');
builder.append(dashdash);
builder.append(boundary);
builder.append(crlf);
builder.append('Content-Disposition: form-data; name="'+ this.config.name +'"');
if (file.name) {
builder.append('; filename="' + file.name + '"');
}
builder.append(crlf);
builder.append('Content-Type: application/octet-stream');
builder.append(crlf);
builder.append(crlf);
/* Append binary data. */
builder.append(file.blob);
builder.append(crlf);
/* Write boundary. */
builder.append(dashdash);
builder.append(boundary);
builder.append(crlf);
/* Mark end of the request. */
builder.append(dashdash);
builder.append(boundary);
builder.append(dashdash);
builder.append(crlf);
return {
builder: builder,
boundary: boundary
}
},
/* ====== for html5Binary ======= */
html5Binary: function (e) {
var _this = this;
if (e.dataTransfer.files.length == 0) return;
this.preventDefault(e);
var file = e.dataTransfer.files[0];
var b = this.binaryBuild(file.name, file.getAsBinary());
this.xhr.onloadstart = this.config.onloadstart;
this.xhr.onuploadprogress = this.config.onprogress;
this.xhr.onreadystatechange = function () {
if (_this.xhr.readyState === 4) {
_this.config.oncomplete.call(_this, _this.xhr.responseText);
}
}
this.xhr.open('POST', this.config.action, true);
this.xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + b.boundary);
this.xhr.setRequestHeader('Content-Length', file.size);
this.xhr.overrideMimeType('text/plain; charset=x-user-defined-binary'); //read.readAsDataURL(file);
this.xhr.sendAsBinary(b.builder);
},
binaryBuild: function (name, binary) {
var boundary = '--fileupload'+(+new Date),
dashdash = '--',
crlf = '\n';
var builder = '';
builder += dashdash;
builder += boundary;
builder += crlf;
/* httprequest header */
builder += 'Content-Disposition: form-data; name="'+ this.config.name +'"';
if (name) {
builder += '; filename="' + encodeURIComponent(name) + '"';
}
builder += crlf;
builder += 'Content-Type: application/octet-stream';
builder += crlf;
builder += crlf;
/* build Binary data */
builder += binary;
builder += crlf;
/* Write boundary. */
builder += dashdash;
builder += boundary;
builder += crlf;
/* Mark end of the request. */
builder += dashdash;
builder += boundary;
builder += dashdash;
builder += crlf;
return {
builder: builder,
boundary: boundary
}
}
})
this.DDUpload = DDUpload;
})();
比较惊讶的一点是http 请求头的创建,格式还真奇怪,非要 -- 和换行结合,且不像js一样支持分号... 汗,算我少见多怪吧...